问题一:JVM频繁FULL GC快速排查和内存泄露
在分享此案例前,先聊聊哪些场景会导致频繁 Full GC:
- 内存泄漏(代码有问题,对象引用没及时释放,导致对象不能及时回收)
- 死循环
- 大对象
尤其是大对象,80% 以上的情况就是它,那么大对象从哪里来的呢?
- 数据库(包括 MySQL 和 MongoDB 等 NoSQL 数据库),结果集太大
- 第三方接口传输的大对象
- 消息队列,消息太大
常规做法:
一般先用 jmap 导出堆内存快照(jmap -dump:format=b,file=文件名 [pid]),
然后用 mat 等工具分析出什么对象占用了大量空间,
再查看相关引用找到问题代码。或者在监控后台查看IO异常信息
问题二:幂等性问题
每次消费消息给用户增加积分前,先根据订单号查一遍积分记录表,
如果没有积分记录才给用户增加积分。
问题三:缓存雪崩
给RedisKey设置过期时间,可以采用一个较大的固定值加上一个较小的随机值。
比如过期时间可以是:24 小时+0 到 3600 秒的随机值。
问题四:磁盘 IO 导致线程阻塞
写一个shell脚本自动定时执行 jstack,5 秒执行一次 jstack,
每次执行结果放到不同日志文件中,只保存 20000 个日志文件.
下一次响应变慢的时候,我们找到对应时间点的 jstack 日志文件,发现里面有很多线程阻塞在 logback 输出日志的过程。
后来我们精简了 log,并且把 log 输出改成异步,问题解决了,这个脚本果真好用!建议大家保留,以后遇到类似问题时,可以拿来用!
#!/bin/bash
num=0
log="/tmp/jstack_thread_log/thread_info"
cd /tmp
if [ ! -d "jstack_thread_log" ]; then
mkdir jstack_thread_log
fi
while ((num <= 10000));
do
ID=`ps -ef | grep java | grep gaea | grep -v "grep" | awk '{print $2}'`
if [ -n "$ID" ]; then
jstack $ID >> ${log}
fi
num=$(( $num + 1 ))
mod=$(( $num%100 ))
if [ $mod -eq 0 ]; then
back=$log$num
mv $log $back
fi
sleep 5
done
问题五:数据库死锁问题
两条SQL语句同时批量操作同一个表中数据,由于执行顺序不一致,导致相互等待。
解决办法就是从 SQL 语句上保证加锁顺序一致。
或者其中一条SQL每次只能操作一条记录,然后在程序里多次循环执行 SQL,
如果批量操作的记录数量不多,这种笨办法也是可行的。
问题六:域名劫持
由于当时的 CDN 图片链接采用了不安全的 HTTP 协议,所以很容易被劫持。后来改成了 HTTPS,问题就解决了。
当然域名劫持有很多方式,HTTPS 也不能规避所有问题。所以,除了一些安全防护措施,很多公司都有自己的备用域名,一旦发生域名劫持可以随时切换到备用域名。
问题七:带宽资源耗尽
网络带宽直接被打满,由于带宽资源被耗尽,导致很多页面请求响应很慢甚至没任何响应。
原因就是二维码生成数量瞬间翻了几十倍,每个二维码都是一张图片,对带宽带来了巨大压力。
怎么解决呢?如果服务端处理不了,就考虑一下客户端。把生成二维码放到客户端APP处理。
可以充分利用用户终端手机,目前 Andriod,iOS 或者 React 都有相关生成二维码的 SDK