前言
这篇来讲解线上环境遇到问题,并如何解决,大概从内存,cpu,无响应、以及多线程和最优多线程性能问题来解决
一、内存泄漏和内存溢出区别以及怎么优化
1.1、定义
- 内存泄漏:是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出。
- 内存溢出:申请内存前,系统已经不能再分配出你所需要的空间,保OOM错误。
1.2、内存泄漏可以分为4类
- 常发性内存泄漏:发生内存泄漏的代码,每次被执行的时候都会导致一块内存泄漏。
- 偶发性内存泄漏:发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。
- 一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。
- 隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。
1.3、内存溢出可能情况
- 检查对数据库查询中,是否有一次获得全部数据的查询。
- 检查代码中是否有死循环或递归调用。
- 检查是否有大循环重复产生新对象实体。
- 检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。
1.4、内存溢出解决办法
- 修改JVM启动参数,直接增加内存。(-Xms,-Xmx参数一定不要忘记加。)
- 检查错误日志,查看“OutOfMemory”错误前是否有其 它异常或错误。
- 对代码进行走查和分析,找出可能发生内存溢出的位置。
- 使用内存查看工具动态查看内存使用情况
二、生产服务器CPU突然利用率高
遇到原因
- 程序计算比较密集:任务调度和业务逻辑拆分,任务调度底层死循环
- 程序死循环
- 程序逻请求堵塞
- IO读写太高
- 设置网关、过滤、保证接口幂等性问题
- 被攻击,高并发。安装服务器监听工具,设置提醒
linux排查
- 先找到Java的进程号
top -c 查看CPU使用率高的进程的PID
- 找到里面是哪个线程占用率最高
top -H -p <pid> 查看该进程所有线程信息,找到占用率最高的那个
- 得到线程号的16进制
printf "%x\n" <pid>
- 分析dump查找问题代码片
可以用 jstack <pid> | grep -A <tid> 来实时获取内存中该线程代码片,这里<tid>是第3步中得到的16进制的id
- 分析dump文件
- 启动jvisualvm,并查看目标java进程信息,然后选择Sampler -> CPU -> Thread CPU Time
三、应用无响应如何处理
服务器没有及时线程池处理请求:走服务熔断,降级返回友好提示,代码将低耗时的代码采用异步(MQ、多线程)执行
四、多线程访问接口注意哪些事项
- 当多线程访问一个接口,有可能遇到线程安全。此时应使用lock锁和sys锁
- 如果接口耗时久,可以将耗时代码改成异步处理(MQ,多线程)
- 接口幂等性问题:
- 如果接口是insert,根据全局ID做唯一约束
- 如果update情况,根据版本号解决防止ABA
- 安全相关防护,防止攻击
五、如何最优提高多线程性能问题
- 使用线程池复用机制,不建议单独创建线程,从而提高多线程效率
- 建议使用乐观锁CAS,自旋,不建议使用悲观锁(乐观锁:消耗cpu,不阻塞,悲观锁:有阻塞)
- 使用sys锁时,尽量降低锁的持有时间,使用偏向锁和轻量锁,否则变为重量级锁情况,效率低(偏向锁–>轻量锁–>短暂自旋–>重量级锁阻塞)
- 使用锁的采用分段锁,减少锁的粒度
- 最好使用多核服务器,避免频繁切换上下文
六、文件过大
分析
查看储存大小
df -h
使用这个发现不太明显知道那个目录下文件过大
linux 怎么定位那个目录文件最大
du -ha /path/to/directory | grep -v "/$" | sort -rh | head -n 5
- du -ha /path/to/directory: 这个命令将给出目录 /path/to/directory 中所有文件和子目录的大小,-h 参数表示以人类可读的格式显示文件大小,-a 参数表示列出所有文件和子目录。
- grep -v “/$”: 这个命令将删除它的输出中所有文件夹,只保留文件。
- sort -rh: 这个命令将输出按照文件大小逆序排序(从大到小)。
- head -n 5: 限制这个命令的输出只返回文件大小最大的前 5 个文件。
- 您可以将/path/to/directory替换为您希望查找的目录路径。执行命令后,它将输出目录中最大的文件的路径和大小。
到这一步发现三个文件过大,那就是程序日志、/var/log/journal/ 和mysql binlog日志文件过大
如果 /var/log/journal/ 文件夹变得过大,可能是由于日志不断累积导致的。在这种情况下,您可以通过一些方法来解决问题:
删减不必要的日志文件:使用 journalctl 命令来检查和删除一些不必要的日志文件,可以使用 --vacuum-size 参数来指定愿意释放的磁盘空间,例如 journalctl --vacuum-size=100M 表示释放100MB的磁盘空间。
调整 journald 的日志最大大小:通过修改 journald.conf 文件来调整日志的最大大小限制,可以使用命令 systemctl edit systemd-journald.service 在编辑器中打开配置文件。在配置文件中添加以下配置:
[Journal]
SystemMaxUse=50M
这表示 journald 系统最多可以使用50MB空间来存储日志。修改保存并重启 journald,使用 systemctl restart systemd-journald.service 命令即可。
调整日志的过期时间:可以通过修改日志最大存储时间来解决问题,配置项为 MaxRetentionSec=。例如若要限制日志的最大存储时间为一个月,可以使用如下配置:
[Journal]
MaxRetentionSec=1month
完成配置后,保存修改并重启 journald 服务。
MySQL 的二进制日志(binary log)包含了对 MySQL 数据库所有写操作的记录。因此,二进制日志对于数据恢复和复制是非常重要的。但是,如果不进行定期清理,二进制日志可能会占用磁盘空间并影响性能。以下是清理 MySQL 二进制日志的步骤:
查询当前的 binlog 日志文件:
SHOW BINARY LOGS;
确定要保留的 binlog 日志文件。通常,您需要保留最近的几个 binlog 日志文件。例如,如果要保留最新的 3 个日志文件,则可以使用以下命令:
PURGE BINARY LOGS TO 'mysql-bin.000007';
以上命令将在删除 mysql-bin.000007 日志文件及其之前的所有日志文件。假设 mysql-bin.000007 是当前日志文件,那么这个命令将清除日志文件 mysql-bin.000001 到 mysql-bin.000006。
使用以下命令可以清除所有旧的 binlog 日志:
PURGE BINARY LOGS BEFORE NOW();
以上命令将删除在当前日志文件之前的所有 binlog 日志文件。
注意:在清理 binlog 日志之前,建议使用 mysqlbinlog 工具备份所有的二进制日志文件,以便在需要时进行数据恢复。此外,建议定期备份数据库以保障数据安全。
解决
最后分别处理三个日志
- 服务器日志
直接使用rm 删除
- /var/log/journal/
查看前几名最大文件
删除命令 journalctl --vacuum-size=100M
- mysql binlog日志
SHOW BINARY LOGS;
PURGE BINARY LOGS TO 'binlog.000070'; -- 该名字是删除该名字之前的日志