秒杀性能优化实践总结

来源:互联网 发布:iphone5s没有4g网络 编辑:程序博客网 时间:2024/05/21 06:55
经历了几个月的秒杀优化,终于可以应付几千个用户并发秒杀的情况,用户量继续增长的情况下,这种思路应该也是可以继续支撑的。下面总结了这段时间的优化所采取的具体措施。

问题分析和解决的总体方法:
日志分析、统计各个接口的调用次数和平均耗时、找出问题所在。总的来说,就是要找出瓶颈,然后在两方面解决这个瓶颈:
  • 提高这个瓶颈的吞吐量
  • 通过限流和削峰,限制等待这个瓶颈的线程数

具体的优化包括:代码优化、服务器架构(隔离)优化、项目配置优化、前端优化、以及产品设计优化、等。

1、代码优化
少用事务(提高吞吐量):
由于事务会到最后才释放所有的数据库连接,所以如果一个事务中需要多个连接,就会慢慢用光了连接数;而且事务需要启动和释放,需要耗费系统资源。所以,应该筛查代码,只针对需要同时更新两个数据、而且需要保持一致性的方法使用事务;就算需要事务,也要缩小事务的影响范围,比如只应用在那两个写操作中,对于它们前面和后面的数据库操作,可以放在事务之外。对于完全是读取、或者只有一个更新操作的方法,不应该使用事务。

使用缓存(提高吞吐量):
尽可能多地使用缓存,避免过多的请求跑到了数据库:
  • 本地缓存:对于那些基本上不会更改的数据(比如系统字典、地区表),可以存放在Java应用中,比如Guava Cache或者自己利用ConcurrentHashMap实现一种本地缓存(需要考虑实现失效的机制);另外一种可以存放本地缓存的数据是不需要跨服务器共享的数据,比如一个接口的请求结果,如果可以缓存几十秒,将可以极大地降低数据库的压力(但需要考虑缓存的命中率,只有这些数据的key是有限的情况下,命中率才会高)。Guava Cache提供了缓存命中率统计的方法,可以很方便的监视缓存的使用情况,以便及时调整。
  • redis缓存:用来存放需要在服务器间同步的数据,比如库存量、购物车数量、排队的请求、正在处理中的请求数、需要被异步处理的信息(比如短信通知内容)、用户最后登录时间、等等。对于库存量这种需要线程间同步的数据,可以使用Redis LUA脚本来保证操作的原子性。

削峰:
对于需要排队处理的请求(比如更新库存量),需要限制排队的人数。有两种方法:
  • 队列法:把请求放进一个队列之后立即返回,另外一个线程处理队列中的请求,成功后异步通知用户(实现异步通知比较麻烦);
  • 变量法:在redis中设置一个变量,当一个请求到达的时候incr这个变量,并得到incr的结果;如果发现结果已经超过最大限制数,则返回告诉用户队列已满;如果结果没超过最大限制数,则处理这个请求;不管处理结果如何、是否发生异常,都decr这个变量(可以放在finally语句中)。这个也可以使用LUA脚本,减少和redis交互的次数。

2、服务器架构优化
增加服务器、调整服务器权重(提高并发处理的吞吐量):
  • 如果tomcat集群中的所有服务器的CPU负荷已经达到100%,需要考虑往集群中添加机器;如果只是某个服务器负荷达到了100%,则可能是这个机器的CPU比较弱,可以调低Nginx中路由到这个集群的权重
  • 如果数据库从库负荷已经达到了100%,需要考虑增加从库机器;
  • 如果数据库主库的负荷已经达到了100%,需要考虑分库分表。

服务隔离:
将秒杀相关的服务隔离到一个独立的服务器中,以避免拖死其他服务。

数据库隔离:
独立出一个从库专门为秒杀提供查询,以避免拖死其他服务,而且便于查询问题。

3、项目配置优化
数据库连接池:
观察是否有异常的log有“SQLTimeoutException: Timeout after 30000ms of waiting for a connection.”其中30000ms对应于datasource中的连接池参数"connectionTimeout"。
如果有这种情况,调查出异常的方法中使用了哪些datasource,适当调大相应的datasource的maximumPoolSize。
注:出现这种情况,应该优先考虑提高业务的处理速度并且考虑削峰和限量。如果数据库连接池太多,会导致数据库花太多的时间来检查死锁、以及在各个线程之间的切换,最终可能会拖死数据库。

Tomcat配置:
根据tomcat服务器的cpu使用率,调整maxThreads参数,缺省是200。在秒杀的时候监视线程使用的情况(可以通过tomcat manager监视),如果cpu利用率没达到100%但是线程已经被用光了,可以调高这个数。
注:线程被用光的一种可能是系统有太多的IO阻塞,即系统遇到了某个瓶颈,这时候在tomcat增加线程数是没用的,新启动的线程还是会被阻塞。解决的方法应该是考虑提高瓶颈的吞吐量、或者削峰处理。

4、前端优化
  • 限制用户刷新的频率;
  • 友好的提示;
  • 精简、合并接口调用的次数;

5、产品设计优化
  • 提供用户直接进入秒杀页面的入口,而不用多次跳转后才进入到秒杀页面;
  • 秒杀流程精简化,避免多次操作、跳转后才能秒杀成功;





1 0