我当时迷迷糊糊爬起来,拿笔记本连了他那台阿里云2核4G的入门级ecs,先查了top命令,好家伙,MySQL进程占了90%多的CPU,load average直接飙到12.7,远超2核的警戒值太多。别不信,真的有80%的新手小团队,刚开始上线电商小网站,都只会用一键安装包搭个默认配置的MySQL,连基本的慢查询日志都没开,硬件不够直接想着加钱升配置,这其实是最浪费钱的。
先帮他先把慢查询日志开起来,敲黑板,这个是入门级MySQL优化的第一步,没有慢查询日志你根本不知道哪里慢,都是瞎猜。 操作其实很简单,先看一眼他的my.cnf配置文件,一键安装包默认在/etc/my.cnf,vim进去加了这几行:
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow-query.log
long_query_time = 2
log_queries_not_using_indexes = 1
加完记得重启MySQL服务,systemctl restart mysqld,还特意给他科普了一下,long_query_time设置成2秒是因为小电商网站用户等待超过1.5秒就大概率会流失,但别设置得太低,不然日志生成太快占磁盘。

然后等重启后阿凯把直播回放那段时间段的慢查询日志导出来,用mysqldumpslow工具简单排了个序,mysqldumpslow -s t -t 10 /var/log/mysql/slow-query.log,这个命令就是按查询时间倒序,取前10条最慢的。
排出来的结果一看,全是三条SQL拖的后腿:第一条是实时查“这个商品sku剩余可售库存的,第二条是查询用户历史三个月订单列表的,第三条就是刚才直播弹幕说的最多的、把购物车商品加入到待结算页关联sku信息的。先看查库存那条SQL,居然是对整个商品库存表做全表扫描!他说开发的时候为了图省事,没给商品库存表的product_sku的product_id和sku_id加联合索引,我上个月刚处理过一起和这个几乎一模一样的库存卡崩的场景,也是朋友创业做生鲜电商。
这里给新手运维或者兼顾的后端提个醒,库存表这类高并发读写的表, product_id+sku_id绝对是要先建联合索引的, 别单独建product_id或者单独建sku_id,单独建一个的话,这条SQL可能还是会扫半表,效率提升不大。 建索引的命令也很简单,先备份一下product_sku表:mysqldump -u root -p kaifahao shop_product_sku > /root/backup_202X0X0X.sql,密码输完备份好之后,直接建:CREATE INDEX idx_product_sku_stock ON shop_product_sku(product_id,sku_id)。
然后看第二条SQL更离谱,查用户历史订单是SELECT FROM shop_order o LEFT JOIN shop_order_item i ON o.id = i.order_id WHERE o.user_id = ? AND o.create_time > DATE_SUB(NOW(), INTERVAL 3 MONTH),这条SQL居然没有给user_id和create_time加联合索引,还SELECT ,把用户的身份证号、收货地址的备用联系人这些冗余字段全查出来了,而且左连接是先查order再查item,其实对于高并发场景下,可以适当的冗余字段在order表,或者用JOIN的顺序调整一下,但那天时间紧,先加个user_id+create_time的联合索引,并且把SELECT *改成只查需要的id、order_no、total_amount、status、create_time,然后item表只查product_name、sku_name、quantity、price:
CREATE INDEX idx_user_create_time ON shop_order(user_id,create_time);
第三条SQL和前两条差不多,给购物车表的user_id加了,但没给关联商品信息的联合索引,也是先备份了之后,加了idx_cart_user_product_idx?不对,建联合索引idx_cart_user_id_product_id。
这三条索引建完之后,用explain语句分别查了一下,Type从ALL变成了ref或者range,rows也从几万条降到了几十条甚至个位数。让阿凯赶紧把刚才的慢查询日志清掉,重新开了个500人左右的内部小范围测了一下,点立即付款只需要1秒多,查购物车库存毫秒级就出来了,后台load average也稳定在0.8左右,MySQL的CPU使用率降到了10%到20%浮动。那天虽然不是工作日,阿凯赶紧开了个限时折扣挽回了一些客户,后来算下来转化率提升了至少60%多。
说实话,中小团队刚开始上线服务器,硬件不是万能的,很多时候卡单不是CPU不够内存不足,只是默认的MySQL配置没调,该加的索引没加,该关的慢查询日志没开。那天帮他之后,我帮他把默认的buffer_pool_size也调了一下,阿里云2核4G的ecs,buffer_pool_size设置成内存的一半到七成,我个人 是六成,也就是2.4G左右,因为还要留内存给nginx和php-fpm。
你们在运维工作中有没有遇到过类似的MySQL卡单、MySQL卡崩的场景?欢迎在评论区分享你的排查经验或者踩过的坑。

评论列表 (0条):
加载更多评论 Loading...