【腾讯Bugly干货分享】微信mars 的高品质日志模块 xlog

正文来源于腾讯bugly开发者社区,未经小编同意,请勿转载,原文地址:http://dev.qq.com/topic/581c2c46bef1702a2db3ae53

Dev Club
是一个互换活动开发技术,结交朋友,增添人脉的社群,成员都是通过审批的移位支付工程师。周周都会举行嘉宾分享,话题研商等活动。

本期,大家邀请了 腾讯 WXG Android
高级工程师“闫国跃”,为大家享受《微信mars 的高质量日志模块 xlog》。


大家好
我是来源于腾讯微信的闫国跃,很荣幸能给大家做那几个分享,我明日主要给大家享用微信mars
的高品质日志模块 xlog 

1. Mars 简介

率先介绍一下mars 是何许。

mars 是微信官方的顶点基础零部件,是一个利用 C++
编写的营业性无关,平台性无关的底蕴零部件。 

可以看一下mars 简单的架构图:

图片 1

从图中就足以见到它主要概括以下几个部分:

  1. comm:可以独自使用的公共库,包涵 socket、线程、音讯队列、协程等
  2. xlog:可以单独运用的日记模块
  3. sdt:可以独立使用的网络诊断模块
  4. stn:可以独自运用的信令分发网络模块

当下连着平台:Android、iOS、Mac、Windows、WP等
。现正在筹措开源中。可以如此说,接入 mars
之后,开发一个应用只须要把开发主导放在业务层和 UI
层上,底层的日记模块和互联网模块在 mars 中都早就提供。

在拔取用户数上有月活跃8亿的微信用户支持背书(数据来自财报)。
在数额监控上,纯网络监督,长连接有18项 短连接7项。

接下去自己最首要讲前日的中坚mars的 xlog
部分。大家先来合计一下为什么需求日志,日志曾几何时能突显其意义。

2. 为啥要求 xlog

大家来看一下微信早期跟进难题的流程是怎么样的: 

图片 2

当用户举报或者我们发现难题时,大家须求互换用户,用户承诺合营后,然后修改代码打开日志重新编包让用户准备再次出现难点,再现之后才能一连排查。那一个流程是由当时选取的日记方案所决定的。例如
Android 平台应用 java
达成日志模块,每有一句日志就加密写进文件。那样在利用进程中不但存在多量的
GC,更致命的是因为有恢宏的 IO 要求写入,影响程序质量很简单导致程序卡顿。

选拔那种方案,在 release
版本只好选取把日志关掉。不仅定位难题的功效低下,而且并不可能确保每个须求一定的标题都能再次出现。这么些方案得以说根本是为顺序公布前服务的。

在紧接着往下讲从前,大家先来分析一下以此日志方案所存在的题材。那一个日志方案首要的标题就是性质太差。首要质量瓶颈是出现在屡次写文件上。写文件的大概流程如下图: 

图片 3

当写文件的时候,并不是把数据直接写入了磁盘,而是先把数量写入到系统的缓存(dirty
page)中,系统一般会在下边三种情况把 dirty page 写入到磁盘:

  • 定时回写,相关变量在/proc/sys/vm/dirty_writeback_centisecs和/proc/sys/vm/dirty_expire_centisecs中定义。
  • 调用 write 的时候,发现 dirty page
    占用内存超过系统内存一定比例,相关变量在/proc/sys/vm/dirty_background_ratio(
    后台运行不封堵 write)和/proc/sys/vm/dirty_ratio(阻塞
    write)中定义。
  • 内存不足。 

数量从程序写入到磁盘的长河中,其实牵涉到五回数据拷贝:四遍是用户空间内存拷贝到根本空间的缓存,三回是回写时内核空间的缓存到硬盘的正片。当发生回写时也关系到了基石空间和用户空间频仍切换。

dirty page 回写的机会对应用层来说又是不可控的,所以品质瓶颈就涌出了。

再就是相对于固态硬盘,SSD 存储还有一个“写入放大”的题材。那一个题目根本和 SSD
存储的物理构造有关。当
SSD被全部写过两回之后,再写入的多少是不得以一向更新,只好透过覆盖重写,在覆盖从前须要先擦除数量。但写入的细无反相机位是
Page,擦除的纤维单位是 Block,而 Block 远大于
Page,所以在写入新数据时就要求先把Block
上的数量读出来和要写入的数目统一在联合,再把 Block
擦除,最终把读出来的数码重复写入到存储上,那样造成实际写入的多少或许远远不止最开始需求写入的多寡。 

举个最简便易行的事例:

当要写入一个 4KB
的多少时,最坏的景观是一个块里已经远非到头空间了,但有无效的数据可以擦除,所以主控就把所有的数目读到缓存,擦除块,缓存里
更新任何块的数额,再把新数据写回去,这几个操作带来的写入放大就是: 实际写
4K 的多寡,造成了一切块(共 512KB)的写入操作,那就是加大了 128
倍。同时还推动了原本只必要简单一步写入 4KB 的操作变成:闪存读取
(512KB)→缓存改(4KB)→闪存擦除(512KB)→闪存写入(512KB),共四步操作,造成延迟大大增添,速度变慢。 

只是简单的写文件就牵涉到这么多的购销,那几个时候大家初步认识到一个高性能日志模块的严重性,既然每个平台都亟需打印日志,那为啥不开发一个通用的日记模块呢。 

在做事先,大家要考虑的一个相比首要的题材就是一个高品质日志模块须要达成怎么着意义?需求有哪些方面的保管?是还是不是曾经有古已有之轮子可用了?

先是来看一下相比流行的服务端日志框架都提供了怎么职能,如 Log4j, LOGBack
帮忙socket读写 帮助直接写多少库 使用XML配置 针对一种日志抽象层完毕(如
SLF4J) …… 

可是由于终端设备的碎片化,用户的多元化,使用情状的复杂化,大家必要的日志组件: 
首先是有限帮忙流畅性,使用进程中不可能影响程序的特性。因为对此一个 App
来说,流畅性尤为重大,流畅性直接影响用户体验,最基本的流畅性的承保是应用了日志不会促成卡顿,不过流畅性不仅囊括了系统绝非卡顿,还要尽可能有限扶助没有
CPU 峰值。 
而且要确保日志的完整性,任何时刻都有日记可查。无法因为程序被操作系统杀掉或者发生了未捕捉到的
Crash 就丢了有的日记。 
还有相比强的容错性,当日志文件中的部分日志数据损坏时应当尽量最小化对总体日志文件的影响。 
最终保障要求的安全性,日志内容必要开展加密。 以上能够计算我们须求一个
保障流畅性的前提下,高完整性,强容错性,要求的安全性的日志组件。 

服务端日志框架提供的效能和我们需求的效能相比较可以看看,现有的日记框架很难满意大家终端设备的必要,所以大家开始初步造轮子。为了合营多平台,大家接纳了
C++举办开发,即便并不是持有的函数都在 Android、iOS、Windows
等系统上通用,但多数接口其实是通用的,大家只须求封装个其余阳台相关接口就行了。

3. xlog-V1.0 方案

还记得最简易的日志方案是什么的:对每一行日志加密写文件。
在这几个方案中因为要写入大批量的 IO
导致程序卡顿,这是或不是可以先把日志缓存到内存中,当到一定大小时再加密写进文件,为了越发回落要求加密和写入的数额,在加密前面可以先举办削减。 

本着那个想法就提出了xlog V1.0的方案。

方案描述:把日记写入到作为 log 中间 buffer
的内存中,达到自然标准后减弱加密写进文件。  那个方案的中坚流程图如下: 

图片 4

其一方案基本可以解决 release
版本因为流畅性不敢打日志的标题,并且对于流畅性解决了最重视的一些:由于写日记导致的程序卡顿的难点。不过因为压缩不是
realtime compress,所以如故存在 CPU 峰值。

但以此方案却存在一个沉重的标题:丢日志。

突出中的情况:

当程序 crash 时, crash 捕捉模块捕捉到 crash,
然后调用日志接口把内存中的日记刷到文件中。不过实际上运用中会发现先后被系统杀死不会有事件通报,而且许多万分退出,crash
捕捉模块并不一定能捕捉到。而那二种状态恰恰是日常跟进的最紧要,因为尚未
crash 堆栈协理定位难题,所以丢日志的难点那个时候显得尤其呈现。 

在事实上履行中,Android 可以使用共享内存做中间 buffer
避免丢日志,但任何平台并从未太好的主意,而且 Android 4.0
将来,大多数手机不再有权力行使共享内存,  即使在 Android 4.0
从前,共享内存也不是一个国有接口,使用时只好经过系统调用的艺术来行使。

所以那些方案照旧存在欠缺:

  • 固然破坏一部分数目即使不会累及所有日志文件但会影响总体压缩块。
  • 个别意况下仍然会丢日志,而且集中压缩会促成 CPU 长时间飙高。 

以此方案微信使用了很长的日子,但随着
Android系统的升官,该方案已经不能够满意使用须要了。再回头看后边多少个方案,直接写文件即使不会丢日志但会潜移默化属性,使用内存做中间
buffer 缓存日志可能会丢日志。 

4. xlog-V2.0 方案

若是得以把那八个方案的亮点糅合在一齐,就是大家真的必要的一个完好无损的日记方案了。一个既有直接写内存的特性,又有平素写文件的可信性的方案。也就是微信近年来在用的xlog的方案。

4.1 mmap

为了兼顾流畅性和完整性,大家引入了 mmap,mmap
是使用逻辑内存对磁盘文件举行映射,中间只是举行映射没有其他拷贝操作,防止了写文件的数额拷贝。 操作内存就相当于在操作文件,幸免了水源空间和用户空间的再三切换。 

图片 5

为了验证 mmap
是或不是真的有一向写内存的成效,大家写了一个概括的测试用例:把512
Byte的多少分别写入150 kb大小的内存和 mmap,以及磁盘文件100w次并总计耗时 

图片 6

从上图看出mmap大概和间接写内存一样的特性,而且 mmap
既不会丢日志,回写时机对我们的话又基本可控。 mmap 的回写时机:

  • 内存不足
  • 进度退出
  • 调用 msync 或者 munmap
  • 不设置 MAP_NOSYNC 情况下 30s-60s(仅限FreeBSD) 

如若得以经过引入 mmap
既能保险高品质又能担保强完整性,那么还设有的其他题材啊?比如集中压缩导致
CPU 长期飙高,那几个标题从上个方案就径直留存。而且动用 mmap
后又引入了新的题材, 可以看一下应用 mmap 之后的日记模块流程:

图片 7

前边已经介绍了,当程序被系统杀掉会把逻辑内存中的数据写入到 mmap
文件中,那时候数据是当面的,很简单被窥探,可能会有人觉得这在写进 mmap
从前先加密不就行了,但是那里又必要考虑,是压缩后再加密依旧加密后再压缩的难题,很了解先削减再加密效用比较高,那几个顺序不可能更改。而且在写入
mmap 从前先举行压缩,也会压缩所占用的 mmap 的轻重,进而收缩 mmap
所占据内存的高低。所以最终只得考虑:是或不是能在写进逻辑内存在此以前就把日志先举办压缩,再展开加密,末了再写入到逻辑内存中。难题显明了:就是怎么对单行日志举办压缩,也就是其余模块每写一行日志日志模块就不能不进行压缩。 

4.2 压缩

带着那个标题 我们去看一下减去,相比较通用的回落方案是先举行短语式压缩,
短语式压缩过程中有多个滑动窗口,历史滑动窗口和前向缓存窗口,在前向缓存窗口中经过和野史滑动窗口中的内容举行匹配从而举行编码。 

图片 8

比如说那句绕口令:吃葡萄不吐葡萄皮,不吃葡萄倒吐葡萄皮。中间是有两块重复的情节“吃葡萄”和“吐葡萄皮”那两块。首个“吃葡萄”的长短是
3 和上个“吃葡萄”的离开是 10 ,所以能够用 (10,3)
的值对来代表,同样的道理“吐葡萄皮”可以轮换为 (10,4 ) 

图片 9

这么些没压缩的字符通过 ascci 编码其实也是 0-255
的平头,所以通过短语式压缩获得的结果实质上是一堆整数。对整数的缩减最普遍的就是
huffman 编码。通用的压缩方案也是那般做的,当然中间还掺杂了游程编码,code
length
的更换。但实际上那些不是关爱的要紧。大家只须要驾驭整个压缩进程中,短语式压缩也就是
LZ77
编码完结最大的缩减部分也是最首要的部分就行了,其他模块的压缩其实是对那几个压缩结果的尤为缩减,进一步压缩的办法重点行使
huffman
压缩,所以那边就必要依据数字出现的频率举行统计编码,也就是说如若滑动窗口大小没上限的前提下,越来越多的数据汇总压缩,压缩的机能就越好。日志模块使用这些方案时也就是xlog
V1.0方案时压缩效果可以直达 86.3%。

既然 LZ77 编码已经做到了多数精减,那么是或不是足以弱化 huffman
压缩部分,比如选用静态 huffman
表,自定义字典等。于是大家测试了两种方案: 

图片 10

此地可以看出来后二种方案鲜明优于前二种,压缩率都可以直达
83.7%。第三种是把全部 app
生命周期作为一个缩小单位展开削减,若是那一个压缩单位中有数量损坏,那么后边的日志也都解压不出去。但实质上在短语式压缩进度中,滑动窗口并不是可是大的,一般是
32kb
,所以只需求把自然大小作为一个回落单位就足以了。那也就是第多少个方案,
那样的话就算压缩单位中有一对数据损坏,因为是流式压缩,并不影响那些单位中损坏数据此前的日志的解压,只会潜移默化那几个单位中这几个损坏数据未来的日志。 

对于使用流式压缩后,大家采纳了三台安卓手机举办了耗时计算,和事先使用通用压缩的的日志方案展开了对待(耗时为单行日志的平均耗时): 

图片 11

透过横向比较,可以见到即便接纳流式压缩的耗时是利用多条日志同时削减的 2.5
倍左右,可是这一个耗时我就很小,是阿秒级其他,大概不会对质量造成影响。最要害的,多条日志同时削减会造成
CPU
曲线长时间内极速提升,进而可能会招致程序卡顿,而流式压缩是把日子分散在方方面面生命周期内,CPU
的曲线更平整,相当于把裁减进度中使用的资源均分在整个 app 生命周期内。

4.3 xlog 方案总括

统计一下方案,也就是xlog 的末段日志方案:

利用流式压缩格局对单行日志进行削减,压缩加密后写进作为 log 中间
buffer的 mmap 中,当 mmap 中的数据到达一定大小后再写进磁盘文件中

即使选取流式压缩并不曾达标最出彩的压缩率,但和 mmap 一起行使能全职流畅性
完整性 容错性 的前提下,83.7%的压缩率也是能承受的。使用那些方案,除非 IO
损坏或者磁盘没有可用空间,基本可以有限支撑不会丢掉任何一行日志。 

在架构设计上也设想了扩大性,比如日志尾部的结构体是足以擅自修改的 

图片 12

出口到文件的最紧要落成是在 Appender
模块也是可插拔的,如若对默许的方针不乐意可以自己完成一套。 

图片 13

xlog还留存有的其余策略:

  • 老是启动的时候会清理日志,幸免挤占太多用户磁盘空间
  • 为了防患 sdcard 被拔出导致写不了日志,辅助设置缓存目录,当 sdcard
    插上时会把缓存目录里的日记写入到 sdcard 上
  • ……

在动用的接口方面支撑各样金童玉女情势:

  • 花色安全检测方法:%s %d 。例如:xinfo(“%s %d”, “test”, 1)
  • 序号匹配的点子:%0 %1 。例如:xinfo(TSF”%0 %1 %0”, “test”, 1)
  • 智能匹配的懒人情势:%_ 。例如:xinfo(TSF”%_ %_”, “test”, 1) 

5. 总结

说到底, 对于极端设备来说,打日志并不只是把日志音信写到文件里这么简单。除了前文提到的流畅性
完整性
容错性
,还有一个最重点的是安全性。基于哪怕被破解,但也无法任哪个人都能破解的条件, 对日记的标准比加密算法的选料更为首要,所以那边并没有座谈那点。

在此此前方可以见见,一个可观的顶点日志模块无论怎么规划都无法不形成:

  • 不可以把用户的心曲音信打印到日志文件里,不可能把日志明文打到日志文件里。
  • 无法影响程序的特性。最主旨的保管是运用了日志不会招致程序卡顿。
  • 无法因为程序被系统杀掉,或者暴发了 crash,crash
    捕捉模块没有捕捉到导致一些年华点没有日记,
    要有限辅助程序整个生命周期内都有日记。
  • 不可以因为有些数据损坏就影响了整个日志文件,应该最小化数据损坏对日记文件的震慑。

地点这几点也即直接强调的 安全性 流畅性 完整性 容错性
它们中间存在着争辨关系:

  • 只要一贯写文件会卡顿,但如果应用内存做中间 buffer 又或许丢日志
  • 假诺不对日记内容开展削减会招致 IO
    卡顿影响属性,但借使缩减,部分损坏或者会潜移默化所有压缩块,而且为了增大压缩率集中压缩又或者引致
    CPU 长时间飙高。

6. mars 开源安顿

mars
安插在岁末开源,方今在走审核流程。运作形式方面,会确保开放出来的代码和微信在运用的代码是同源的。具体开源时间以微信终端官方公众账号为准。

图片 14

自己的分享就到这边,谢谢我们。

互相问答

Q1:crash捕捉模块具体能分解下嘛?

crash捕捉模块不在mars开源之列,能够线下互换,若是想捕捉C++ crash
提议看Android 源码 backtrace和libunwind方面。 若是是Java的Crash
我不大擅长,就不作答了。

Q2:应用那么些日志对劳动器端有啥样须求?

持有的日志行为都是在终点上,严酷说来和服务端没有别的关系。

Q3: 安卓上调用C++打日志还有没有JNI的特性难题啊

在最初的Android
系统上JNI的特性的确是有些难题的,不过随着谷歌认识到C++高质量的特色一向在那方面做相关优化。
现在Java调用C++性能消耗基本得以不考虑。而且实际Java的应用层接口调用到底层也基本都是C来完毕的。

Q4:日志尾部的magic number 有何样出力?

此处有七个成效,1. 足以看来日志尾部是没安装版本号的,所以是依照magic
num做了版本有别。 2.
压缩加密后的日志存到文件里,再去解压,是要分别日志开首地点,以及是还是不是损坏的。

Q5:感谢嘉宾精彩分享,收益很多,我的题材是,日志存储到sdcard后还会发送到服务端吗,若是发送在怎么时机,假如不发crash新闻怎样及时通晓。

客户端的日记绝大部分时间应该安安静静的在用户手机上等待超时被删去,倘使某个用户有报告,因为日志本身是个文件,用户可以经过行使把那一个文件主动上传出服务器。
比如 微信 也有特定的命令用户输入后会触发上报。
至于crash音信,crash捕捉模块捕捉到
可以crash的时候同样打印到日志文件里,而且crash新闻也理应单独于日志的一个模块,那一个应该是必须上报的。

Q6:这么些log重若是储存哪些首要信息,是不是可以自定义一些数目存储?
比如app有局地特有的多寡也想写进log

不得以的。 除非自己转换成string的描述。即便一个对象
也足以把对象里的本位属性打印到日志里。
仍然强调的一个点:日志规范很关键,不仅在于安全还在于 只打有用的音讯。

Q7:我想问下加密这几个环节,是对(多条日志压缩后的结果)举行加密吗,也就是说压缩后的日志要高达一定的轻重才会展开加密吗?假使是crash的时候,压缩后的日记没有达到这几个尺寸,是怎么处理的吧?

不是的 你或许清楚错了。你说的那几个方案是xlog
V1.0的方案,你说的更加场合也正是以此方案被丢掉的由来,在V2.0方案会每写一行日志都会间接压缩加密写进mmap中。

Q8:关于日志的上传,是不是在此开源之中?关于申报日志,有何样的构思?比如时间,传输优化,收到后的解压等难题?

不在
毕竟外部也不容许把你们的日志放心交给大家。关于反映日志,要考虑上报有失败的恐怕,所以须求重试,不过牵涉到相比较大的数目,所以重试要有上限。考虑到服务器收到到数量须求仓储,使用十二线程上报速度会所有进步。因为数据量相比较大
最好把公文分片后再上传, 甚至足以考虑断点续传。

Q9:请问下mars和bugly有啥样异同?各自有怎么样优势?

Bugly近年来重中之重是那多少个申报服务,就是Crash监控。这一块是不包蕴在mars里的。三个是补充的关联。
mars主要涵盖的成效是 日志
信令互联网通道,网络检测以及部分跨平台C++的基础库。都是在微信内拔取的源码。

Q10:xlog log存储到内存中,大小怎么总计,会按照手机适配吗?

此时此刻分配内存150kb,不会依据手机举行适配。
这么些总结形式是大家根据此前的测试的削减数量来反推的。

Q11:对于xlog中的加密以及裁减能够独立接口使用呢?

加密部分自己不希望大家关怀,那也是本身享受中一贯不享受的原故。因为自己咱们不应该把用户的隐私数据打印到日志里。
所以最后开源大家不提供加密算法,但会提供自己达成加密的接口。
那两块都不提供单身的接口使用,压缩除了极端气象下并从未如此用的必不可少,毕竟超过半数意况下是已知多少之后才开展的要说。

Q12:xlog是平台毫无干系的,为何介绍提到Android的优化

叩问安卓和iOS三个平台的人会精通最难伺候的是安卓平台,给后台运行权限又保留随时杀掉你的职责。
丢日志在安卓平台更加频仍。

Q13:请问下地面存储日志时可不可以选取数据库而不用文件?要求传给服务器时再查询数据库?

不太提议客户端的日志存在数据库里,有些服务器的日记放在数据库是因为为了持续分析应用。
不过大家清楚多少大点的数量都不用放到数据库
更何况是日记文件呢。而且存到数据库会招致有大气的数据库操作,那几个特性要考虑。
最终 一个日志模块 我还索要拖一个sqlite的源码进去
o(╯□╰)o,我们期望这些模块精简到无可精简的境地, 近年来xlog
的so大小是120kb

Q14:单行压缩的第八个方案,说累积压缩后到一定大小,作为一个收缩单位,是何意啊?mmap回写
是系统的行为?要求我们也为这一个进度做些工作啊?

前方有张图说短语式压缩其实是有五个滑动窗口,其实是要按照历史数据开展匹配。可是考虑到性能滑动窗口并不是然则大,所以历史数据也没必要给太多。一个削减单位意思就是减弱状态初阶化到竣事。
回写基本可以整个交付系统,我们要求做的历次启动程序去读取mmap文件看是或不是有上个程序生命周期没写进文件的多少


越多赏心悦目内容欢迎关心bugly的微信公众账号:

图片 15

腾讯
Bugly
是一款专为移动开发者营造的质量监督工具,支持开发者快速,便捷的定位线上利用崩溃的动静以及解决方案。智能合并成效匡助开发同学把每一天上报的数千条
Crash
依据根因合并分类,每一天早报会列出影响用户数最多的垮台,精准定位功能扶助开发同学定位到出标题标代码行,实时举报可以在揭发后很快的打听应用的身分情状,适配最新的
iOS, Android 官方操作系统,鹅厂的工程师都在行使,快来到场大家啊!

网站地图xml地图