java-线上问题排查
一、RT(响应时长)飙高
排查链路
查看kibana/grafana监控图(查看接口RT整体情况和飙高临界时间点) -> kibana查询典型案例请求(查看具体RT时常并提取请求响应参数) -> pinpoint(查看访问链路中耗时过长的请求节点/RT飙高的请求是否都集中于同一主机或节点) -> 分析解决
问题一:下游接口RT耗时过长
原因:通过从pinpoint链路分析可以得知耗时过长的请求点,代码追踪定位到是因为调用外围系统接口且其RT过慢导致。
解决:联系外围接口相关负责人进行排查并协助解决问题。
问题二:单主机/节点网络问题
原因:通过pinpoint/kibana中可以获取请求打入的主机/节点,通过分析发现所有RT飙高的请求都集中在同一个主机下。而后登陆主机进行网络测试发现,问题主机的网络响应时长明显高于其他主机,定位问题是因主机网络导致。
解决:联系运维人员紧急修复网络问题并同步清理当前主机硬盘内存释放空间,同时上报问题,批准后在ng先剔除当前主机节点或者分配新的主机节点。
问题三:代码问题(慢查询)
原因:通过pinpoint链路分析可以得知耗时过长的请求点,代码追踪定位发现是新业务代码存在慢查询的问题。
慢查询原因:1、查询数据是通过上游同步而来,本次上游同步了新数据,导致cache缓存刷新,业务场景需要重新查询数据库。
2、本次针对特殊产品场景新增了一个查询字段,该字段未设置索引,虽然之前有聚簇索引且该查询也走到了聚簇索引,但是根据索引查询后的数据还是N+万需要再次根据新增字段筛选。(结果集过滤)2点原因导致RT飙升
解决:添加索引,避免后续因慢查询过多导致mysql连接池打满,从而影响其他业务工程。
二、数据库锁表
排查链路:
业务接口异常 -> kibana查询异常描述 -> 查询主机日志获取异常详细的堆栈描述 -> 数据库表测试
问题一:版本发布时出现批量业务失败
原因:版本发布时进行了DDL操作,更新了表结构(新增索引),因为表数据量较大,需要执行几分钟,期间持续占用MDL锁(表级锁)。此时因为有业务写/读(因为MDL锁被占用从而进行阻塞)导致锁表。
解决:1.业务量不大时,等待DDL操作结束后释放MDL锁,然后失败业务会自动进行补偿。
2.业务量大时,使用Mysql自带的在线DDL操作,即DDL同时允许读写操作。(ALGORITHM=INPLACE, LOCK=NONE;)
问题二:全局扫描导致行级锁升级
原因:update 的where条件中附含like的后缀匹配(前缀走索引、后缀不走)且没有其他索引相关的查询条件,导致sql进行了全表扫描,全表扫描和update会对表逐行加锁,甚至可能导致全表加锁。业务进行写操作时,会影响效率甚至导致阻塞,造成“假锁表”的现象
解决:用limit分段执行、添加索引条件
三、数据库连接池打满
排查链路:
查看主机业务日志/kibana查看异常日志 -> 查看数据库日志
问题一:连接数设置异常
原因:春节活动数据库连接池打满,因为某工程的数据库连接数设置有问题
解决:更改工程配置
问题二:慢查询导致
原因:春节活动压测环节出现大批量异常,最终在主机日志发现是因为连接池打满,修复数据库重启服务后发现业务流程正常,而后通过分析数据库日志定位存在慢查询。最终定位慢查询来源于grafana监控(很多监控sql未走索引,其中还有一个因为不符合)。
解决:优化sql,走索引,将grafana默认查询时间段缩小
特殊化(最左匹配):监控中有一条sql,其where含有索引字段,但是仍然为慢sql,通过查询执行计划得知,因为创建的是联合索引,而它不符合联合索引的最左原则匹配原则导致sql实质未走索引。(索引:CREATE INDEX idx_name_age_city ON tb_user_info(user_name, age, city); sql:where number = ’‘ and user_name = '' and age = ’‘ and city = ’‘)
解决:新建索引(CREATE INDEX idx_number_name_age_city ON tb_user_info(number, user_name, age, city);)
特殊化(group by未走索引):错误日志并不是想往常提醒time-out,而是提醒【排序失败:操作终止】,原sql是一个含有where和group by的,因为group by的原因,结果集会进行隐式排序。
出现当前错误无非3个点:1.慢sql 2.人为终止sql(排除)3.数据库资源/负载问题(排除,因为数据库其他操作正常)。
最终确定是慢sql导致,因为where条件是走了索引,但where条件查出的结果集比较大,而group by条件未走索引,所以导致慢sql(例: where user = '' and city = '' group by age, city limit 1000, 索引只有user)
解决:创建一个age和city的联合索引/创建一个user、age、city的联合索引(一定要符合最左原则)
特殊化(group by导致索引改变):数据库为了优化二次排序,如果group by的字段有索引,sql会优先使用group by的索引,因为索引是天然有序的。(select * from tf_b_order where age= '' and city = '' and id >= '' and sex = '' order by id limit 100)
走了id的主键索引后,虽然不用回表了,但是因为where中还有其他条件且不包含在本次走的索引内,所以还会根据where的条件对首次id的结果集进行二次筛选,首次查询结果集本身就很大 还要进行二次筛选,导致慢查询。
解决:1.force INDEX(idx_tf_b_order_sex)指定索引
2.修改group by的列
特殊化(回表):查询sql走了索引,但是只走了二级索引(非聚簇索引),二级索引实际只会存储索引值+主键的值,所以当查询结果集有其他字段诉求时,会进行回表操作,补全数据。
解决:1.sql不要使用select *
2.补全/创建联合索引
特殊化(索引失效):索引列参与计算导致不走索引。(age +1 = 12会影响,age = 12 + 1不影响)
特殊化(索引失效):索引进行了函数操作。(YEAR(create time)= 2025)
特殊化(索引失效):OR 且两边存在<>判断(a = 1 or b >2会导致索引失效, a = 1 or b = 2不会失效)
特殊化(索引失效):like后匹配导致未走索引(like '%a'不走索引,like ‘a%’走索引)
特殊化(索引失效):is not null导致索引失效
特殊化(索引失效):in导致索引失效(in后条件过多会导致索引失效)
问题三:事务耗时过长
原因:新上线了一个订单流程 主要涉及订单库,上线后发现订单库相关工程频繁出现连接池打满的情况,最终通过代码分析得出订单所有入库处理均在一个事务中,事务过大 耗时过长导致连接池占满。
解决:拆分优化入库事务,分层入库。
问题四:锁等待
原因:同【数据库锁表】中的问题二
解决:优化监控sql
四、数据库CPU飙升
排查链路:
查看相关中间件监控 -> 查看mysql主机 -> 分析规律
原因:
版本日通过监控发现mysql的cpu呈规律性飙升,虽然都在可控范围内,但飙升较为明显。
后续单例核查mysql主机发现其网络、内存、配置等均无问题,查询数据库日志发现业务明显慢查询,最后通过提取cpu飙升时间段发现可能跟新上的【风控用户拉取】需求有关(cpu飙升时间点和【风控用户拉取】定时任务的时间节点完全吻合),然后关掉相关定时任务观察确认CPU飙升确实由新需求导致。
而后分析相关sql发现,cpu飙升原因是因为锁等待导致(定时任务拉取风控系统的相关数据,我们通过某一维度查库并入库整合,但是因为存在批量的用户恶意刷单、刷风控导致当前用户下数据较多,且存在并发情况,导致update同一用户数据时发生锁等待情况(InnoDB会在update的时候自动给行记录加锁,以防止其他线程同时更新该行记录。其他行操作需要等待锁))
解决:
不再进行单条数据操作(比如用户的A风控记录也查库改库、B风控记录也查库改库),而是先把所有拉取数据放入一个新的中间表,然后对中间表数据进行聚合操作,将聚合后的结果一次性更新即可。
五、OOM问题(文件导出)
排查链路:
用户反馈异常 -> 日志排查(OOM)
原因:
各省负责人可以导出全省运营点即所含渠道相关信息,随着项目沉淀和数据沉淀,陆续反馈文件导出系统频繁奔溃。
查询相关主机日志发现虚拟机error日志抛出oom,分析文件导出系统并查阅得知,因为使用了XSSFWorkbook,而且是一次性将所有内容加载到SXSSFWorkbook中,其占用内存较大且释放靠GC处理,用户同时间段大批量使用则导致OOM。
解决:
起初方案打算优化为SXSSFWorkbook,因为其是存放在磁盘中,但考虑到后期数据越来越多会导致导出速度过慢,最终选择了最原始的CSV技术,它采用流式存储且输出较快。
六、网络问题(B/S浏览器-服务器、C/S用户端-服务器)
排查链路:
排查我们的代理主机 到 目标主机网络情况(ping) -> 排查代理主机 到 目标主机指定端口网络情况 (telnet) -> 排查接口访问权限情况(curl)
原因:
对接下游接口时,发现主机网络不通,有时只核查了ping 导致端口不通或者接口无权限
解决:
ping -> telnet -> curl
七、服务节点突然挂掉
排查链路:
服务出现批量异常 -> 通过pinpoint核查异常数 -> 通过pinpoint查看异常原因(not found host......) -> -注册中心检查工程部署节点
原因:
1.假死,通常因为(死锁、活锁、无限等待、阻塞等),可以先去注册中心看节点是否存在,如果存在就去kibana/主机日志查看相关异常,然后kill掉节点,定位异常代码点。
2.主机/节点挂掉,通常因为(OOM、资源不足:CPU或者磁盘被打满、宿主机挂了),可以去注册中心查看节点是否存在/在pinpoint查看是否存在大量not found host......
解决:
假死 - 定位假死原因,修复问题代码
主机/节点挂掉 - OOM时增加JVM堆内存、资源不足时及时清理主机硬件资源或扩充、宿主机挂了就核查具体原因并重启
八、活动服务kafka首次连接耗时超长
排查链路:
代码中新增耗时统计 -> kibana中统计耗时情况 -> 联系kafka提供方协助排查
原因:
通过观察发现Kafka在工程重新部署后,首次连接耗时30S以上,本次接入新kafka,该kafka新增了安全认证以及消费者权限认证,导致首次连接超时
解决:
按照提供方建议,新增相关hosts配置
九、春节活动的定时任务+转单主机挂掉
排查链路:
注册中心查看服务节点
原因:
定时任务使用了线程池,因为定时任务数量庞大且执行频繁,导致达到了主机线程池的上限,最后导致10台主机挂了8台
解决:
修改主机线程池最大数
取消定时任务线程池的使用
十、kafka位移重置导致从头开始消费
解决:
auto.offset.reset=earliest 替换为 auto.offset.reset=latest
1,earliest 当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从头开始消费
2,latest 当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,消费新产生的该分区下的数据
十一、数据库入库异常(字节超限)
排查链路:
查看主机日志,发现报错(Cause: java.sql.SQLException: Incorrect string value: '\xF0\xA3\xB2\x99' for column 'cert_name' at row 1)
原因:
mysql中的utf-8并不是真正意义上的utf-8,它只能存储1~3个字节长度的utf-8编码。而用户输入了特殊表情,实际是4字节,导致报错。
解决:
使用utf8mb4类型(首先要保证Mysql版本要不低于 MySQL 5.5.3)
前端限制
十二、号码和短信服务QPS飙升
排查链路:
通过kibana查看服务请求信息,通过IP、参数、响应结果、时间等参数进行判断,是业务量起来了还是被DDOS攻击了
原因:
因为请求量是日常的N倍,且存在大量相同IP,参数也存在大量异常。所以推断出受到DDOS攻击。
解决:
将IP/用户添加至服务黑名单
新增短时间内同IP/用户请求上限校验
十三、支付问题(1.用户仍能支付超时退单的订单 2.支付侧显示【已支付】 调用方仍为【未支付】)
(1)原因:
用户拉起支付后,过了40分钟才进行了付款,而订单30分钟后就自动超时退单了,但支付侧未及时失效支付页。
(1)解决:
联系支付侧及时失效支付页面
(2)原因:
1.网络问题导致
2.异步处理导致的结果延迟(支付侧收到支付请求后进行异步处理,先响应成功后处理,当没有处理完成时调用方就发起了回调,回调结束后支付侧又处理成功了)
3.回调失败
4.支付侧存在问题
(2)解决:
逐一排查
更多推荐


所有评论(0)