==============================请看上篇===================================
1.日志分类
(1)按产生的来源:系统日志、容器日志、应用日志
(2)按应用目标:性能日志、安全日志
(3)按级别不同:调试日志、信息日志、警告日志、错误日志
2.对于计数器日志、响应时间日志、异常日志,方法入参和返回值等有规律可循的通用日志,可以使用AOP技术的切面编程来打印。
对于业务代码中比较复杂的业务信息,可以直接在代码中打点。
3.Log4j的锁和性能优化
(1)Log4j默认的Appenders使用同步锁来实现,并发时线程都在等待一个写日志事件的锁。
(2)对Log4j进行改进:同步操作改为异步操作,例如可以使用一个缓冲队列,业务线程仅将日志事件放入缓冲队列就返回,然后用单独的消费者线程去消费缓冲队列,异步将缓冲队列的日志内容打印到日志文件。
(3)为了达到较高的性能,使用一个无限循环的线程,批量检查日志缓存队列时是否有日志事件,如果有就批量消费和打印日志。
(4)Disruptor RingBuffer是一个优秀的无锁队列,从设计模式上是观察者模式。
4.Log4j2的异步记录日志功能通过在一个单独的线程里执行I/O操作来提高性能,有两种实现方式:异步Appender和异步Logger。
5. 日志系统的优化和最佳实践
(1)打印日志时必须包含环境信息,例如:用户ID、角色、参数、返回值、逻辑判断结果、循环次数、异常信息等。
(2)必须使用占位符的方式代替字符串连接。
(3)对关键业务步骤必须打点并记录耗时和结果等信息。
(4)Log4j是通过构建异常从异常堆栈中提取方法名、文件名和行号的,需要耗费很多时间和资源。因此,不推荐在日志中使用%L、%M、%F、%l占位符来显示方法名、文件名和行号等,但可以使用%c来打印类名。
(5)toString()方法的实现需要考虑连接字符串是否可能产生NullPointerException,对可能为空的字段先判空后再进行打印。
6. ELK系统
Elasticsearch、Logstash和Kibana
1.APM系统
应用性能管理系统,开源的有Pinpoint、Zipkin和CAT。
2.分布式系统的远程调用过程
(1)服务于一个用户请求的内部服务调用结构是一个树型结构
(2)在谷歌的 Dapper论文中,每个节点都对应一个Span,节点之间的连线表示Span和它的父Span之间的关系,具体表现为一次调用请求和响应的调用关系。
(3)通过增加应用层的标记来对服务化中的请求和响应建立联系。例如,它通过HTTP协议头携带标记信息,标记信息包括标识调用链的唯一流水ID(为TraceID),以及标识调用层次和顺序的SpanID和ParentSpanID。
3. TraceID和SpanID在服务间的传递
(1)Java进程内传递
通过ThreadLocal
(2)服务间传递
HTTP方式:请求头增加TraceID和SpanID
RPC方式:在RPC的序列化协议上增加定制化的字段
(3)主子线程间传递
(4)消息队列的传递
在每次发送消息时将TraceID和SpanID增加到消息报文中,在消息队列的处理机的库中先对报文进行解析,再将业务报文传递给应用层处理。
(5)缓存、数据库访问
4. 采集器的实现方法
(1)应用层主动推送
(2)AOP推送
在应用的业务层代码中使用AOP拦截目标服务调用,把请求和响应的调用信息收集后,推送到调用链处理器。
(3)JavaAgent字节码增强
利用JDK提供的java.lang.Instrument API对加载的类进行过滤,找到我们需要增强的目标服务实现类,在相应的方法上增加AOP切面,把服务调用的发送消息和接收信息进行拦截和收集,并发送到调用链处理器上。
(4)代理推送
Kafka消息队列、UDP推送
1.海恩法则和墨菲定律
(1)海恩法则
1》事故的发生是量的积累的结果
2》再好的技术、再完美的规章,在实际操作层面也无法取代人自身的素质和责任心
(2)墨菲定律
1》任何事情都没有表面看起来那么简单
2》所有事情的发展都会比你预计的时间长
3》会出错的事总会出错
4》如果你担心某种情况发生,那么它更有可能发生
2.线上应急
(1)6个阶段:
1》发现问题
2》定位问题
3》解决问题
对各种严重情况设计止损和降级开关
4》消除影响
5》回顾问题
类似的问题还有哪些没有想到?
做了哪些事情,这个事故就不会发生?
做了哪些事情,这个事故即使发生了,也不会产生损失?
做了哪些事情,这个事故即使发生了,也不会产生这么大的损失?
6》避免措施
(2)总体目标:尽快恢复问题,消除影响
3. 最小化复现
指在个人开发环境内通过模拟生产环境来重现生产环境产生的问题。
4. 产生OutOfMemoryError(OOM)的原因
(1)java.lang.OutOfMemoryError: Java heap space,表示Java堆空间不足。
(2)java.lang.OutOfMemoryError: PermGen space,表示Java永久代(方法区)的空间不足。
(3)java.lang.OutOfMemoryError: unable to create new native thread,本质原因是创建了太多的线程。
(4)java.lang.OutOfMemoryError: GC overhead limit exceeded,是并行垃圾回收器的GC回收时间过长、超过98%的时间用来做GC并且回收了不到2%的堆内存时抛出的异常
5. 使用Dubbo服务框架时,采用自动降级原则,如果Dubbo服务负载增加或者注册中心宕机,则会自动切换到点对点的RPC框架。
============================= 继续看下篇 ==================================