前不久,一个朋友网站出了问题,让我帮忙看看,是一个商城,每天早上9点有一个秒杀活动,每天到点准时卡顿,希望我给点建议。
简单介绍一下优化的过程,和各位同行一起分享。
1. 项目server配置情况
一台mysql server,独立服务器,内存128G,i7 64核,配置比较高
web server 配置一般,10台,跑php-fpm

基础架构图
php-fpm根据配置不同,起的php-fpm进程也不同。
运行情况,平时运行稳定,没什么压力,但每天抢单时,页面就i开始卡顿很长时间,有时还会出错;
web server和db服务器cpu使用率都非常高,达到95%以上,很明显是没有并发能力啦!
php-fpm优化能做的都做了,效果不是很明显,估计应该是mysql遇到瓶颈:
mysql> show status like 'Table%';
+----------------------------+----------+
| Variable_name | Value |
+----------------------------+----------+
| Table_locks_immediate | 10043 |
| Table_locks_waited | 0 |
+----------------------------+----------+Table_locks_immediate 指的是能够立即获得表级锁的次数
Table_locks_waited 指的是不能立即获取表级锁而需要等待的次数
show OPEN TABLES where In_use > 0;
show variables like '%max_connections%'; 查看最大连接数
最大连接数已经达到了4000+,设置的max_connections=5000,感觉已经快达到极限了。
2. 优化第一步,肯定是sql优化了
配置my.cnf
slow_query_log=1
slow_query_log_file=slow.log
long_query_time=2开启后,第二天一看,果然有大量的慢查询,最慢的竟然长达40s之多,在高并发下这种延时累积,系统不崩才怪呢!
日志下载下来,开始分析吧
基本3种情况:
(1) 没有索引,查询条件没有索引进行全表扫描,数据量大了很慢,这种加索引就行了。
(2) sql太复杂,很多类似下面
select * from table where userid in (select user_id from table2 where ...)这种就尽量拆开,分成简单的sql,在php代码中处理。
(3) 数据量大,有些log数据,有几千万条,这些数据参与了逻辑判断,如判断登录次数,第几次登录等这种场景,可以分成冷热数据,就拆成了两个表了。
经过优化,读的问题有很大的改善。
3.增加从库,读写分离
为了减轻MySQL的压力,增加了两台从库,配置和主库一样,都是高配。
代码配置

主从配置图

主从架构图
增加了两台从库后,主库的压力依然很高,从库压力很小了,cpu只有20%多。
通过增加从库,我们达到了两个目的:
a. 提供了db读能力
b. 降低了写锁冲突
问题
1.为了避免实时读数据延迟,有些读操作仍然走的master主库,这也是主库压力大的一个因素;
2.数据唯一性问题 ,主从数据有差异,有些大表的记录数有很小的出入,当更新、删除从库不存在的记录,会导致同步失败。每次重新同步就要晚上停服,同步,再启动,让人很不爽!
4. 引入redis
虽然系统性能有了很大的改善,但高峰期依然压力大,还没有解决根本问题。于是决定引入redis,redis有两个作用。
(1) cache,能进缓存就放缓存
系统配置,这些也是在mysql ,虽然数据不多,但几乎没什么变化,不需要每次读取;
统计信息,这些不需要实时,而且查询性能较低,可以放缓存。
加索引效果不好的,如有的条件是男女,状态是1、2,这些加了索引收效甚微,也可以考虑结果放缓存。
(2)系统核心是抢单,也是写并发所在,把抢单操作放到redis,理论上并发量可以提高两个数量级。
因为要判断库存、写数据,而redis没有事务控制,如何才能保证不写脏数据呢,
看下面的伪代码

redis抢单
经测试,随着并发量增加,redis事务被打断次数也随着上升,即事务执行失败。所以用redis的事务是不可靠的。
最后,引入框架提供的redis锁 yii\redis\Mutex,具体加锁解锁可以查看源码

redis锁
最终的架构图如下:

加了redis的架构图
最后:分库分表
表的水平切分,如图,把一个表的数据按照算法分到两个表里

分库
这样可以:
a. 降低每个表的容量
b. 提高每个表的读写能力
缺点:增加了系统复杂性,如果读写分离需要增加更多的机器,扩展时要考虑数据迁移等问题;
时间紧迫的情况下,不能快速实现。所以没有实施这项方案。
总结:
1.系统在满足需求情况下,越简单越好。开发维护成本越低,在项目初期一般以业务为主。
2.系统优化优先最简单、最直接的方法,有时简单的方法也很有效。复杂的方案实施起来成本也很高。
你在实际项目中都落地了哪些优化方案呢,欢迎留言一起探讨。
















