t
以上都是通过top命令总体检查,还有以下方法可以也可以查找系统瓶颈: Iostat: 查看系统总体IO情况,不可以通过进程查询; Pidstat:如果需要查看某个进程占用的物理内存和虚拟内存,直接使用 pidstat -r -p pid 1 2查看:1、了解应用和外部接口有哪些交互?是否有异常现象?应用除了处理本身代码逻辑以外,往往还需要和外部服务或者接口通信。通过 netstat -anop | grep pid 就可以发现系统正在和哪些外部接口通信,比如下图中3306的端口显示系统有连接mysql数据库,并且有11个连接。系统有时候报错“has already more than 'max_user_connections' active connections”,这时候通过此命令就可能发现有比较多的连接数,当连接数非常多的时候最大的可能是代码在不停的操作数据库或者有慢SQL导致的连接不释放,也就是说当你发现应用连接数大于日常正常数量的时候,系统的代码可能就有问题。同理,下面第二张图通过netstat -anop | grep 6379得知应用有连接redis.如果要查看某个进程的文件IO情况,可以通过命令pidstat -d -t -p pid 1 5查看:Strace:此命令用来跟踪进程执行时的系统调用和所接受的信号,linux中进程不能直接访问硬件设备,必须由用户态模式切换为内核模式通过系统调用访问硬件设备。通过strace -T -t -f -p pid可以显示具体进程的系统调用情况。 网络IO可以通过cat /proc/interrupts查看,网络IO消耗需要关注网卡中断是否不是均衡的分配到各个CPU,Java应用本身一般不会造成网络IO消耗严重。一般java最常用的网络命令是抓包分析请求内容,比如说需要抓取指定IP的网络包tcpdump -i eth0 |grep "110.3.224.253".步骤四:jstack -l 9739 | grep 2617 来分析这个线程正在做的事情,下图显示是gc线程:1、编程规范
(1)防御式编程,根据有限枚举先处理断言,再处理错误,最后处理正常逻辑,正常逻辑外尽可能多的处理异常分支;
(2)开发自测代码必须有单元测试用例;
(3)新方案引进或者重大变更需要上级审核,比如表结构修改增加、中间件的引进、新项目的搭建等;
(4)上线任何功能都必须考虑实时监控埋点数据;
(5)上线任何功能都必须满足标准日志轨迹输出,把业务日志打印成表格的形式,方便通过实时日志解析展示可视化日志轨迹,方便快速问题订单跟踪;
(6)业务代码中所有SQL耗时打印耗时;
(7)业务代码中关键方法打印耗时;
(8)业务代码中异常栈禁止吃掉,需要打印到输出日志中,方便实时异常字抓取报警;
(9)和第三方接口交互,发生网络异常的地方需要抓取IOException处理,同时打印发生网络异常的URL,便实时异常字抓取报警;
(10)和第三方接口交互,需要设置连接超时和读取超时时间,避免同步线程阻塞;
(11)和第三方接口交互,需要考虑是否需要通过代理出网;
(12)和第三方接口交互,需要考虑是否要相互添加白名单;
(13)和第三方接口交互,需要考虑设置合适的work线程符合第三方并发数量限制;2、安全规范:
—页面请求参数严格限制或者校验处理,防止SQL注入;
页面URL请求做细粒度的权限拦截,防止访问权限过大;
部署在公网的应用做好防止XSS攻击的防范措施;
和第三方系统交互需要互加白名单确保安全;
系统全站提供HTTPS服务;
和第三方系统交互报文需要加密传输;
用户敏感数据做数据脱敏;
预防页面被频繁请求,占用系统资源;
预防API被频繁请求,占用系统资源;3、性能规范:
常见OOM预防
禁止应用中显示创建线程,避免不可控出现unable to create new native thread;
控制select/update/delete/insert的数据级和可变集合的size,避免随着业务增加内存数据量不可控;
页面查询不推荐全表查询,查询通过查询条件限制查询条数;
页面下载条数和下载次数做限制,避免请求过多导致OOM;
SQL优化目标必须满足range、ref或者consts,不可以是all类型,避免慢SQL导致连接数耗尽影响业务功能;
代码书写中考虑MySQL中共享锁和排它锁场景,预防产生死锁;
代码中使用@Transactional要考虑数据库死锁场景;
数据库单表达到一定数据量级需要做分库分表或者冷热数据隔离,避免业务增加带来的性能问题;
尽量避免使用全局变量防止并发出现线程安全问题,从而影响业务;
定时器问题预防
定时器浪打浪情况下,任务重复处理会导致资金风险,建议使用redis避免;
定时器浪打浪情况下,启动多个定时器即默认启动多个线程,影响系统性能;
定时器浪打浪情况下,如果定时任务处理过慢会导致内存耗尽;
避免系统中出现单点故障,包括中间件和应用程序等所有的节点;
能异步处理的别同步处理,异步可以释放线程资源,避免阻塞,提高响应效率;
随着业务量的增加,考虑功能拆分和数据库表拆分,除此支付系统建议按照通道拆分,不同的通道指定独立的work线程,分而治之,避免相互之间影响;提高并发的一个思路就是拆分,拆分后通过异步提高并发效率;
事务中有http调用,严重降低并发能力。事务的原则是事务代码少,快进快出;
当 for update 语句和 gap lock 和 next-key lock 锁相混合使用,又没有注意用法的时候,就非常容易出现死锁的情况。通过业务分析,大量使用锁的目的是用来防重,但是完全没有必要通过悲观锁的方式来解决,可用方法有:redis做分布式锁,主键防重,版本号(乐观锁)防重;
日志打印问题-日志的打印必须是以 logger.error 或者 logger.warn 的方式打印出来,大量大量的日志影响磁盘IO,也会造成线程阻塞;还有Log4j1.2.14 版本使用了 synchronized 锁,大量压测会发现线程处于block状态,需要修改log4j配置,提高并发能力。
4、操作规范
上线功能模块必须进行灰度发布环境,以确保上线不会影响线上交易;
上线功能模块判断是否需要进行额外的压力测试;
上线功能模块判断是否需要考虑模块之间的先后上线顺序;
上线功能模块判断是否需要运营提供额外支持,比如运营后台参数配置等事项;
上线功能模块判断是否需要运维提供额外支持,比如配置网络环境、添加证书秘钥、创建文件目录、添加和删除jar包等事项;
上线功能模块判断是否需要DBA提供额外支持,比如新增模块添加数据库访问白名单、增加数据库连接数等;
上线功能模块判断是否添加了报警功能,包括业务监控、关键字监控、响应码监控等;
上线功能模块判断是否需要执行额外SQL和有执行顺序;
上线后产品是否需要进行业务点验收;
线上功能模块发生事故或者bug,第一响应动作是通过灰度环境恢复系统而不是定位问题;5、交易相关的注意点
对于第三方查询接口查询订单不存在的情况需要设置单独响应码,做特殊报警提醒处理,付款类的交易不可以设置为失败状态,这样可以避免资金重付支付;查询操作本身失败代码异常处理中不可以设置订单失败;
资金类交易订单状态设置是根据第三方响应码设置的,订单状态的设置采用保守策略,对于不确定的状态不可以直接设置失败,这样可以避免资金重付支付;
资金类交易订单需要有额外的主动查询和核对查询,以避免第三方接口异常情况;
资金类交易需要有自动路由切换功能,当第三方接口发生宕机的时候,确保后续交易可以引流到成功的通道;
资金类订单需要考虑并发情况下的重复提交,收款类的交易可以重复提交订单提高成功率然后后续通过补偿机制处理,付款的类交易绝对不可以;
资金类订单需要通过数据库乐观锁库和更新条数来避免并发修改同一条记录,进而避免重复支付产生的资金风险;
核心交易系统需要做到7*24监控室轮流值班,确保交易系统第一时间发现问题修复问题;
核心交易系统需要每天做日志巡检,这种弥补机制可以二次帮助确认系统问题,同时让每个同学更加了解系统;