事故一,jvm相关
- 大对象(运营商数据;数据库查询未加查询条件,结果集过大;第三方接口或异步消息);来回转化
- 死循环;
- 推文并发量大
- String.intern() 导致oom
- static字符串拼接 导致oom
- 堆内存过小
- ConcGCThreads 线程过多,stw,导致性能上不去
- jvm配置问题,堆、对象晋升(进入老年代过快或过慢)
- 额度服务因stw停顿过长导致程序性能不稳定
- 堆外内存过大;
堆外内存,人脸ocr服务,照片上传 排查方法:
事故二:并发多线程问题
- 内存中额度扣减或增加,并行时,最终不一致;
- log4j 1多线程堵塞;
- 多线程静态锁synchronized;
- 消息消费执行顺序不一致 解决:
- 确保执行顺序 -> 设置msgid(rocketMq)或partitionKey (kafka)
- 多线程时,同一个用户确保在一个线程里
- 将额度扣减和增加改为 sql语句执行,利用mysql本身的机制处理
事故三:并发幂等问题
- 额度重复恢复 --> 推入消息队列,做幂等处理
- 用户重复下单 --> 临时表,redis分布式锁
- 本地有序queue 以上方案都需要确保停机数据不丢失
事故四:缓存雪崩
- 同一时间大批量临时额度到期导致
- redis故障 解决:
- 大批量数据刷入缓存,失效时间+一定范围的随机数,错峰
- 针对热点数据或共用数据,定时批量刷缓存
- 针对数据的实时性要求不高的话,可做本地缓存
事故五:redis相关事故
- 代码生成器自带开启事务,导致redis链接未及时释放,无连接可用;
- 缓存共用,某些后台项目使用keys *
- 大对象存储,长时间占用cpu资源和带宽导致redis其他操作大量超时;
- redis缓存不设置有效期;解决:
- 代码生成器默认无事务,并制定规范;
- 自建redis 屏蔽keys操作
- 制定规范禁止大于100kb的数据存储,可以统一缓存工具类限制value大小
事故六:磁盘IO导致线程阻塞,cpu彪高
特征:
- cpu占用过高,gc频繁;
- 发现log4j的线程占用过高;
- 日志文件过大(几十g),同时日志输出延迟;禁止System.out.println,禁止console输出,日志切割
- log4j1.* 并发死锁
事故七:无可用线程可创建
1,appuser启动的项目,默认只有1024,通过ulimit -a查看
2,一台ecs部署多个tomcat,请求量稍微大些的时候会出现该问题
3, open文件的个数;
ps:注意下文件句柄数
事故八:高并发情况下短连接释放过慢,大量链接处于time_wait
操作系统默认 240 秒后,才会关闭处于 time_wait 状态的连接
推荐几篇博文,从根上了解下
从Linux源码看Socket(TCP)的accept
从linux源码看socket(tcp)的timeout
事故九:数据库死锁问题
- 常见给慢sql添加索引或修改表结构,表锁导致慢sql,以及无法insert
- 复杂查询带来的死锁;
事故十:域名劫持
前端h5,引导到联通的广告 更换https
事故十一:宽带资源耗尽
前端访问过慢,10mb带宽升级到100mb(app升级包未用cdn加速,直接在挂在项目的域名下) 外网100mb的宽带
- 静态资源cdn;
- 开启tomcat/ng压缩;
- 增加带宽
事故十二:静态锁导致的并发问题
额度重构,分表后批量生成主键id,静态方法加锁,多线程调用,导致死锁
- 临时去掉静态方法
- 使用雪花算法
事故十三:tomcat配置问题
- maxPostSize=“0” 之前0为不限制,升级一次tomcat版本到7.0.70,0的含义变为了post过来的数据量为0,导致生产服务不可用;
- 多个tomcat部署到一台实例线程数不够用,无法创建本地线程
- tomcat 线程少,acceptCout大,
tomcat优化:
- nio ;
- 线程池数量& acceptCount ;
- gzip压缩
- catalina.out ,日志切割(最好的办法就是不往catalina里输出日志)
tomcat 配置
事故十四 数据库
- 多个业务库共用一个实例,部分业务统计到只数据库cpu彪高;->核心业务库独立;
- 慢sql,无索引,或者索引类型不对;
- 修改库表结构时,锁死;
- 复杂嵌套sql;
- 对查询条件的字段进行函数处理,导致全表扫描;
- 主键非自增,导致数据全表扫描;
事故十五:redis的key已过期,但还能获取
用户请求量,在一段时间内,只能请求2w次,用了一个固定key缓存,到了第二天还有效 当redis的cpu过高的时候,定期删除就不一定启动作用;定期删除& 惰性删除 定期删除: 定期从redis中获取数据,检查并删除,cpu过高时就无法执行,有很大概率能拿到未删除的key 惰性删除:每次get的时候主动去校验,会影响redis的性能,量不大可用
事故十六 同一个用户启动多个dubbo项目;
- dubbo的缓存文件是固定名称和路径的,同一个用户启动dubbo会导致.dubbo文件被覆盖
- 改变缓存文件的名称和路径
事故十七 定时任务中创建线程池;
- 重复创建线程池;
- 导致资源打满,cpu彪高,服务假死;
事故十八,默认超时时间 60秒
导致系统群雪崩;
- 业务板块拆分并独立域名;
- 架构有向无环;
- 对非关键业务熔断,制定统一的业务超时标准;
事故十九 线程池打满
服务调用使用httpclient的线程池模式, 当某个接口慢的时候,导致链接堵塞,直接把所有的线程都耗费掉了,影响了其他的系统调用;
线程池有个配置max-connections-per-route,按接口来,最多能占用多少链接,一般设置为1/2或者1/3
事故二十 消息积压
- 后端消费堵塞(因为内外部系统宕机)
- 新进来的用户处理不了(风控,授信);
- 慢sql+异常重试;
解决
- 修复系统问题
- 水平扩展,修改partition数量增加消费节点(大部分能解决,得注意下游的处理能力,要不然会压垮);
- 直接将挤压的消息读取到一个新的topic,先不影响新用户,再监听新topic(如果后端用线程池不要共用)
- 死信队列
事故二十一 threadlocal事故
当某个用户进入系统时,会将用户信息缓存到threadlocal中一份,开发没有在finally中移除 测试和生产tomcat配置的是线程池,最小线程都是200 当用户使用独立的线程的时候,都没有问题,当线程被重复使用时,就铁定出问题;
时间工具类,未从threadlocal中移除,导致时间不一致
定时任务单节点故障
单节点定时任务故障:
- 系统宕机 --> 健康检查
- 系统正常运行,但定时任务停止 --> 分布式定时、多节点执行,利用分布式锁,只能同时有一台执行(ps 锁一定要设置有效期)
线程池事故
- 使用Executors.newFixedThreadPool 创建线程池,队列是无界队列(Integer.MAX_VALUE),导致oom;
- 使用Executors.newCachedThreadPool 创建线程池,corepoolsize 为Integer.MAX_VALUE
- 核心业务和非核心业务共用线程池,非核心业务堵塞,导致核心业务无法执行(还有spring的@Async注解,类似);
- 定时任务里创建线程池,导致资源不够用,任务处理不及时,导致cpu彪高;
- disruptor 配置
事务里调用接口
接口超时导致事务回滚,导致数据库链接数过多;引起服务排队,获取不到资源:
代码生成器不能生成带事务的代码
其他非技术性事故
- slb白名单 checklist
- 数据库,redis白名单 checklist
- kafka 和ecs不在一个域里,网络不通 checklist
- sql未执行就上线 checklist
- 测试不到位 单元测试规范
- 拆表后dts同步,dba未及时将同步去掉,数据迁移规范化操作;
- 链接和超时时间用默认 checklist;
- topic未创建, checklist;
想了解更多,请关注公众号哦。