《Linux多线程... muduoC++网络库》第五章笔记
《Linux多线程服务端编程:使用muduo C++网络库》
程序日志
日志通常指
诊断日志(diagnostic log) 用于保存诊断信息,方便我们进行日后的一些信息跟踪,错误诊断排查等,也可用于性能分析。
交易日志(transaction log) 用于记录状态变更,可以通过日志回放来逐步恢复每一次修改后的状态。
本章的“日志”为第一种日志通常是分布式系统中事故调查时的唯一线索。
在服务端编程中,日志是必不可少的,在生产环境中应做到"Log Everything All The Time"。对于关键进程,通常记录:
收到的每条内部消息的id(关键字端、长度、hash等)
收到的每条外部消息的全文
发出的每条消息的全文、id
关键内部状态的变更等
每条log需要加入时间戳,以保证完整追踪一个事件的来龙去脉。
诊断日志不仅是给开发人员看的,更多的时候是运维人员看,因此日志内容需要避免误解,避免拖延故障解决时间。
日志库大概分为前端和后端两部分。前端为供应用程序使用的API,并生成日志消息;后端则负责把日志保存到目的地。
在多线程的情况下,前端会在每个线程中调用, 而后端只有一个,难点在于高效地将日志数据从多个前端传输到后端。
功能需求
可能需要的功能:
多种级别,如TRACE、DEBUG、INFO、WARNING、ERROR、FATAL等。
多个目的地,如文件、socket、SMTP等
消息格式可配置
设置运行时过滤器
1->希望能够运行时设置。
2->对于分布式系统,目的地只能是本地文件。支持rolling。
3->不必要且要节省解析开销。
4->编译期确定就足够了。
日志的rolling即日志文件的滚动,可以简化日志归档的实现。rolling的条件一般为文件大小(如超过1G更换文件)、文件时间(每天0点创建新文件)。
日志库一般不包含日志文件的压缩和归档,因为这部分需要处理的实际上不仅限于日志库产生的日志,例如c++和java都会产生日志,那么它们的服务程序可以同时使用这一部分,并且如果需要替换压缩算法或归档策略也不需要修改业务程序。
为了防止日志丢失,muduo库采用两个办法应对:
在程序运行时可以定期将日志内容flush到硬盘。
在Log中记录函数地址,以便在core dump中查找对应位置,从而找到尚未写入磁盘的消息。
日志消息格式有几个要点:
每条日志占用一行,以便使用awk、sed、grep等分析。
时间戳精确到微秒,这样不会有性能损失,并且能使数据更精确。
使用相同的GMT时区,以方便不同区域的服务器的log分析。
打印线程id,以便分析时序。
打印日志级别,定位问题时更关心的是Error信息。
打印源文件及行号,方便定位程序源码位置。
性能需求
高性能体现在:
每秒写几千上万条日志时没有明显性能缺失
能应对一个大量产生日志数据的场景,如1GB/min
不阻塞正常运行的执行流程
在多线程程序中,不产生争用
一些性能指标,如100万条/s或1GB/min,指消耗所有资源的情况下能达到的性能,那么如果一个程序只需要10万条/s的需求,就可以有90%的资源来处理业务了。
提高性能的策略:
短期不变数据使用缓存,如程序id,时间戳的日期和时间两部分变化较慢,一秒之内的日志仅需格式化微秒部分。
使log格式确定,前4个字段长度固定,由此可以对定长内存进行memcpy时会进行inline展开降低消耗。
一些日志消息中出现的源文件名和行数等数据可以在编译期运算。
多线程异步日志
要求线程安全,但不能阻塞业务。
为了达到要求,使用双缓冲技术。
准备两块buffer,buffer A 和 buffer B,前端向buffer A填充数据,后端负责写buffer B的数据到磁盘。
这新建日志消息时是与磁盘操作无关的,并且会在装满buffer后触发后端线程(或到达定时flush时限时)。
如果两块buffer都被填满,使用一个vector记录已填满的buffer指针,并新申请一个buffer用于存储。不过这种情况比较少见。
实现时,使用智能指针管理buffer的生存期。
如果出现bug,导致日志堆积,上述策略会导致数据在内存中堆积,引发性能问题或程序崩溃。muduo库直接丢弃多余的buffer以防止内存占用,将来可以加入网络报警功能来通知人工介入。
others
因为近期事情比较多,拖了可能特别久。。。。sorry for that
#Linux##笔记#