记录一次高并发引发的生产事故的溯源记录

一次高并发抢购活动引发的生产事故的过程分析记录

1.在日志中观察到的不少dubbo超时报错

Caused by: com.alibaba.dubbo.remoting.TimeoutException: Waiting server-side response timeout.

排查过程:数据库sql负载偏高,有接口直接查sql没有加缓存的,数据库瓶颈没办法,一个sql延迟几十毫秒,并发上来以后,就会把总体日后拖了node

缘由分析:redis

1.执行sql没有超时时间,慢就慢了,可是rpc接口和对外接口是有timeout的,单个dubbo服务是的线程池数量是有上限的,spring

2.每一个rpc接口调用1个sql,一个sql延迟100ms,就算一个rpc调用100ms,好比这个进程给的线程数是100,那么一秒钟1000ms/200ms * 100 = 500次,也就是这个rpc接口的性能是500次/秒,刚好可以没有线程阻塞等待处理完毕,当501并发时第501个就会阻塞100ms才能进到rpc中执行代码处理,最后由于sql的超时致使了调用dubbo provider进程阻塞,继而致使rpc外层调用的consumer超时,接口返回异常。sql

将sql所有优化以后,发如今高并发的时候日志中仍是有超时的报错,看问题仍是同样的,最后排查发现是由于A服务对外提供了一个按id查惟一信息的rpc接口,B服务中有逻辑为了获取多个id的信息,循环进行屡次rpc调用。因此若是B服务获取的id信息越多对应的rpc循环调用的次数也就越多,从而B的这个业务操做会更加耗时,最后致使超时问题的出现。数据库

最后把这里优化掉,改为一次rpc调用从A服务中批量拿到所有的数据后再在B服务这里分组依次获取。 缓存

2.修复上面的问题后发现又出现了dubbo线程池满了的报错

\[DUBBO\] Thread pool is EXHAUSTED! Thread Name: DubboServerHandler-ip:70882, Pool Size: 400 (active: 400, core: 400, max: 400, largest: 400), Task: 8640430 (completed: 8640030), Executor status:(isShutdown:false, isTerminated:false, isTerminating:false), in dubbo://ip:70882!, dubbo version: 2.6.2, current host: ip

dubbo线程池满了,咱们经过从新设置线程池大小dubbo.provider.threads = 1000网络

3.调大线程池后又出现了另一个问题,Redis链接数跑满了

org.springframework.data.redis.RedisConnectionFailureException: No reachable node in cluster; nested exception is redis.clients.jedis.exceptions.JedisNoReachableClusterNodeException: No reachable node in cluster

redis链接数跑满了,这个问题寻找了很久,最终发现是Jedis的版本问题版本问题,致使连接没有释放,链接泄露,咱们经过升级jedis版本到2.10.2就解决了这个问题。并发

详情见这里https://blog.csdn.net/RL_LEEE/article/details/99831991ide

4.修复了上面的问题后,又出现了redis链接池跑满了问题

org.springframework.dao.InvalidDataAccessApiUsageException: Could not get a resource since the pool is exhausted; nested exception is redis.clients.jedis.exceptions.JedisExhaustedPoolException: Could not get a resource since the pool is exhausted

redis链接池数量过小了,咱们经过增大spring.redis.jedis.pool.max-idle = 100,spring.redis.jedis.pool.max-active = 100,这两个配置从新进行了调整。高并发

5.链接池跑满了的问题解决了,紧接着又出现了热点Key的分布不均匀的问题

redis.clients.jedis.exceptions.JedisClusterMaxRedirectionsException: Too many Cluster redirections?

这个是一个热点大Key的问题,把一个在高峰期会频繁访问的对象所有缓存成一个大对象放到redis里面,最终致使这个对象的大小超过了5MB,由于redis是单线程,每次读取5MB而后再进行传输,会致使网络io上升,并发数上来后,很容易把热点Key所在的节点给压挂。

解决方法就是将整存整取的大对象,分拆为多个小对象。能够尝试将对象分拆成几个key-value, 使用multiGet获取值,这样分拆的意义在于分拆单次操做的压力,将操做压力平摊到多个redis实例中,下降对单个redis的IO影响。

6.最终,将上面的问题都解决了以后事故得以最终解决,特此记录,备忘。

若是对您有帮助,请不要忘了给翎野君点赞。

相关文章
相关标签/搜索