陆续解决过很多生产问题,每次没有记录过一段时间就忘记了
-
服务启动的时候运行卡住了
- case by case 解决,有时候需要把日志级别改为debug才能看到真正的原因
- 有一次是因为mysql连接密钥错误,导致启动hold住,也没有任何提示
- 有一次是因为封装了BeanDefinitionBuilder来自定义bean,实例类的一个属性变量executor增加了@Setter和@Getter注解,所以要求必须注入一个bean对象,程序定义了多个线程池对象不知道使用哪个,无限循环创建这个bean最后会内存溢出。
- 解决方案一:给某个主线程池加上@Primary注解
- 解决方案二:这个属性不需要直接设为null,beanDefinitionBuilder.addPropertyValue(“excecutor”, null);
-
服务内存溢出
- 查看监控可以看到线程数在不断的增加
- 查看线程总数
- jstack -l {pid} |grep java.lang.Thread.State|wc -l
- top -Hp {pid}
- ps huH p {pid}| wc -l
- cat /proc/{pid}/status
- pstreee -p {pid} |wc -l #需要安装:yum -y install psmisc
- ls -l /proc/{pid}/task|wc -l
- 查看线程总数
- 统计最多的线程名字,看到带有"EDS"名字的线程数很多,这个是订阅服务的线程,原因是每次执行方法都开启了一个服务订阅线程导致
- dump内存使用MemoryAnalyzer分析,mac上安装mat软件分析
case1:写了一个循环处理上亿的数据发现内存得不到泄露,java.lang.StackTraceElement对象有很多,最后用memoryAnalyzer分析出应该是cat记录了所有异常的堆栈信息导致OOM,处理过程中可以调用Cat.getManager().reset();清理异常堆栈
- RabbitMQ消息堆积1
- 查看监控看到有少数线程blocked状态,时间点和停止消费时间点吻合
- 结论:connetcion断开导致consumer的消费线程blocked,应该是RabbitMQ的broker出现故障导致, 参考rabbitmq异常导致线程blocked
- 重启服务问题才解决
- RabbitMQ消息堆积2
- 查看监控tidb更新平均时间达到了600ms,导致消费速度低于生产速度
- 先临时扩容消费者,再根据tidb集群监控看到CPU使用率达到100%, 去tidb管理界面看到另外一条业务线用了很多慢查询,联系他们修正sql
- RocketMQ消息没有发送成功
- RocketMQ Producer没有找到namesrvaddress导致发送失败,失败没有剖出异常
- producer没有设置instancename,rocketmq开源版本的clientConfig实例之间需要靠instance name来区分,否则会复用同一个底层的instance对象。实际是由于有一个consumer没有设置namesrvaddress导致producer的namesrvaddress时效了
- Mongodb查询超时
- 给一个复杂查询的所有字段都设置了索引,因为有一个字段用了$in查询,所以导致索引失效
- 解决方案:索引中删除$in查询的字段
- Thrift请求参数丢失【gson反序列化thrift对象时基础类型变量丢失】
- 现象: thrift服务端接口,我调用都正常,但是第三方调用的时候缺失了一个int类型的参数,第三方把请求对象打印出来和断点调试都能看到有这个int参数变量,但是可以确定的是thrift客户端缺失了参数
- 可以借助arthas工具,watch命令观察thrift调用的参数和返回
watch com.xxx.NettyClientRequestInvoker invokeOnce "{params,returnObj}" 'params[0].serviceName equals("server1")' -x 2 -b
, 在请求调用前确实没有参数 - 仔细看第三方的代码,用了gson反序列化对象,断点调试的时候字段确实有值,但是thrift对象的isSetXXX()是false,导致thrift对象在传输的时候忽略了这个变量
- 原因分析:Thrift请求丢失字段(记一次坑爹请求),thrift optional字段设置时,只能用__set_xx()赋值,否则无效,gson反序列的原理是使用反射给变量字段赋值的
// com.google.gson.internal.bind.ReflectiveTypeAdapterFactory类内部代码
return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {
void read(JsonReader reader, Object value) throws IOException, IllegalAccessException {
Object fieldValue = mapped.read(reader);
if (fieldValue != null || !isPrimitive) {
field.set(value, fieldValue); // gson反序列化时使用反射直接给变量赋值
}
}
thrift生成的类里面的StandardScheme会对基础类型变量判断是否设置过值isSetXXX
private static class UserStandardScheme extends org.apache.thrift.scheme.StandardScheme<User> {
public void write(org.apache.thrift.protocol.TProtocol oprot, User struct) throws org.apache.thrift.TException {
struct.validate();
oprot.writeStructBegin(STRUCT_DESC);
if (struct.name != null) { // 对于字符串等基础变量判断是否为null
oprot.writeFieldBegin(NAME_FIELD_DESC);
oprot.writeString(struct.name);
oprot.writeFieldEnd();
}
if (struct.isSetAge()) { // 对于基础类型会判断isSetXXX
oprot.writeFieldBegin(AGE_FIELD_DESC);
oprot.writeI32(struct.age);
oprot.writeFieldEnd();
}
if (struct.address != null) { // 对于字符串等基础变量判断是否为null
if(struct.isSetAddress()) { // 如果字段是optioal的,还要判断isSetXXX,public boolean isSetAddress() { return this.address != null; // 这个方法其实还是判断的字符串是否为null}
oprot.writeFieldBegin(ADDRESS_FIELD_DESC);
oprot.writeString(struct.name);
oprot.writeFieldEnd();
}
}
oprot.writeFieldStop();
oprot.writeStructEnd();
}
}
- 我的服务监控正常但是上游却报错
现象:查看自己的服务接口响应都是正常的,但是上游却报错调用超时
现象分析:比较时间点,虽然自己的接口是在10ms内返回,上游请求时间是10:00:00.000,超时时间是10:00:05.000,但是看自己的服务响应其实是10:00:06.000开始-10:00:06.010结束
可能原因:中间件打点监控不是完全合理,没有上游请求发出后到下游接口开始处理之间的耗时监控
- 之前的请求缓冲在队列里面了,线程耗尽了,不能及时响应上游的请求
- 容器所在物理机网络问题,有时候会出现网络抖动,导致下游的输出没有及时传输到上游服务
- app页面在ios上出现了闪烁
现象:前端h5页面发布服务后,只在ios端出现了闪烁
现象分析:前端生产环境回退了服务问题还在、客户端web容器已经2个月没有更新过、在safari浏览器打开不会出现闪烁、在beta环境正常
原因:大佬定位到是反爬组上线了一个新的反爬插件