前言

这篇来讲解线上环境遇到问题,并如何解决,大概从内存,cpu,无响应、以及多线程和最优多线程性能问题来解决

一、内存泄漏和内存溢出区别以及怎么优化

1.1、定义

  • 内存泄漏:是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出。
  • 内存溢出:申请内存前,系统已经不能再分配出你所需要的空间,保OOM错误。

1.2、内存泄漏可以分为4类

  • 常发性内存泄漏:发生内存泄漏的代码,每次被执行的时候都会导致一块内存泄漏。
  • 偶发性内存泄漏:发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。
  • 一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。
  • 隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。

1.3、内存溢出可能情况

  1. 检查对数据库查询中,是否有一次获得全部数据的查询。
  2. 检查代码中是否有死循环或递归调用。
  3. 检查是否有大循环重复产生新对象实体。
  4. 检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。

1.4、内存溢出解决办法

  • 修改JVM启动参数,直接增加内存。(-Xms,-Xmx参数一定不要忘记加。)
  • 检查错误日志,查看“OutOfMemory”错误前是否有其 它异常或错误。
  • 对代码进行走查和分析,找出可能发生内存溢出的位置。
  • 使用内存查看工具动态查看内存使用情况

二、生产服务器CPU突然利用率高

遇到原因

  1. 程序计算比较密集:任务调度和业务逻辑拆分,任务调度底层死循环
  2. 程序死循环
  3. 程序逻请求堵塞
  4. IO读写太高
  5. 设置网关、过滤、保证接口幂等性问题
  6. 被攻击,高并发。安装服务器监听工具,设置提醒

linux排查

  1. 先找到Java的进程号
top -c 查看CPU使用率高的进程的PID
  1. 找到里面是哪个线程占用率最高
top -H -p <pid> 查看该进程所有线程信息,找到占用率最高的那个
  1. 得到线程号的16进制
printf "%x\n" <pid>
  1. 分析dump查找问题代码片
可以用 jstack <pid> | grep -A <tid> 来实时获取内存中该线程代码片,这里<tid>是第3步中得到的16进制的id
  1. 分析dump文件
  2. 启动jvisualvm,并查看目标java进程信息,然后选择Sampler -> CPU -> Thread CPU Time

三、应用无响应如何处理

服务器没有及时线程池处理请求:走服务熔断,降级返回友好提示,代码将低耗时的代码采用异步(MQ、多线程)执行

四、多线程访问接口注意哪些事项

  1. 当多线程访问一个接口,有可能遇到线程安全。此时应使用lock锁和sys锁
  2. 如果接口耗时久,可以将耗时代码改成异步处理(MQ,多线程)
  3. 接口幂等性问题:
  • 如果接口是insert,根据全局ID做唯一约束
  • 如果update情况,根据版本号解决防止ABA
  1. 安全相关防护,防止攻击

五、如何最优提高多线程性能问题

  1. 使用线程池复用机制,不建议单独创建线程,从而提高多线程效率
  2. 建议使用乐观锁CAS,自旋,不建议使用悲观锁(乐观锁:消耗cpu,不阻塞,悲观锁:有阻塞)
  3. 使用sys锁时,尽量降低锁的持有时间,使用偏向锁和轻量锁,否则变为重量级锁情况,效率低(偏向锁–>轻量锁–>短暂自旋–>重量级锁阻塞)
  4. 使用锁的采用分段锁,减少锁的粒度
  5. 最好使用多核服务器,避免频繁切换上下文

六、文件过大

分析

查看储存大小

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'; -- 该名字是删除该名字之前的日志