Glog 是货拉拉移动端监控体系中的日志存储组件,Glog 意即 General log – 通用日志。为了满意咱们对日志格局的多种需求,咱们在存储方法、归档方法上做了一些探索和实践,使得 Glog 的通用性和功能优于常见的日志计划。Glog 现已在货拉拉全线 App 中安稳运行了 1 年多,现在将其开源,咱们期望 Glog 的开源可以为移动开发者供给一种更加通用的日志计划,同时期望 Glog 可以从社区中汲取营养,不断得到优化和完善。GitHub 地址:https://github.com/huolalatech/hll-wp-glog

布景简介

移动端日志体系一般来说,首要的目标是辅佐开发同学排查线上问题,这些问题包含但不限于

  1. 客诉渠道反应的 App 运用问题;
  2. Crash 体系上报的崩溃问题;
  3. 其他线上冒烟问题。

为了可以赶快定位问题,咱们期望可以快速、详细的复原问题现场,这就需求在代码中 App 运行的关键节点埋入日志,将呈现问题时的运行状态快速上报。这对日志体系提出了两个关键的要求,信息完好性以及实时性。 在移动端,公司之前存在一套简略的日志体系,搜集的日志信息比较有限,咱们经过 App 的常见运用流程来看其覆盖的关键节点

货拉拉客户端通用日志组件 - Glog

另外,之前的日志体系只能经过下发使命回捞,实时性较差,还存在 I/O 功能等问题。

为了解决这些问题,咱们开发了新的移动端日志体系,覆盖了上面 App 运用流程的全节点信息

货拉拉客户端通用日志组件 - Glog

另一方面,为了提高日志的实时性,咱们增加了实时日志,经过短轮询来进行定时上报,此外还补充了监控日志来支撑 App 的横向数据比照、评价 App 的功能指标,终究的计划如下

货拉拉客户端通用日志组件 - Glog

体系首要组成包含

  • Android/iOS 上层日志收集 SDK
  • 跨渠道的储存组件 Glog
  • 担任日志存储过滤的日志后端
  • 担任日志展现的日志前端

新的监控体系包含实时性要求较高的实时日志,信息较完好的离线日志以及为大盘数据服务的监控日志

  • 实时日志,快速上传,信息精简,可以接近实时的查看,快速定位、排查用户反应的问题;
  • 离线日志,经过后台使命触发上传,按天归档,作为实时日志的兜底,要求信息完好详尽;
  • 监控日志,支撑采样,作为监控大盘的信息源,实时性要求最高,日志只包含监控信息。

为了适配不同日志的存储格局,咱们期望存储组件可以在格局上尽量通用,最好做到格局无关;另一方面咱们也期望其功能、牢靠和安全方面可以对齐一线水平,在调研了市面上盛行的日志组件后,咱们发现并没有现成计划满意咱们的需求,因而咱们自研了自己的日志存储组件 Glog。

货拉拉客户端通用日志组件 - Glog

计划概览

运用上层对不同类型的日志序列化(推荐 Protobuf)之后,将二进制数据存储到 Glog,关于上传频次较高的实时日志和监控日志,选用重命名缓存的方法快速归档;关于信息较全而上传频次不高的离线日志,咱们选用 mmap 偏移映射的方法归档,相较规范 I/O 仿制归档的方法,提高了功能。在牢靠性和安全性方面咱们也学习了当时的盛行计划,例如 mmap I/O 提高功能和牢靠性、流式的加密和紧缩避免 CPU 突发峰值,另外咱们在日志中参加了同步符号支撑读取容错。

存储方法

为了适应不同的日志格局,Glog 存储二进制数据,上层根据自己的需求,将数据序列化后交给 Glog

货拉拉客户端通用日志组件 - Glog

详细的文件格局:运用 2 个字节描绘每条日志长度,在每条日志结尾参加一个同步标志,用于文件损坏时的读取容错。

货拉拉客户端通用日志组件 - Glog

归档方法

回忆一下常见的日志组件中 mmap 的运用方法,首要 mmap I/O 需求映射一片巨细为 page size (一般为 4KB) 整数倍巨细的缓存,跟着数据的写入将这片空间耗尽后,咱们无法继续扩展这片空间的巨细(因为它占用的是 App 的运行内存空间),因而需求将其间的数据归档,常见的方法是将其间内容 flush 追加到另一个归档文件当中,之后再清空 mmap 缓存,这个 flush 的进程一般运用规范 I/O

货拉拉客户端通用日志组件 - Glog

而咱们的实时、监控日志为了快速上传确保数据实时性,选用距离较短的轮询来触发 flush 并上传,这将导致 flush 频率变得很高;而一般的 flush 方法选用规范 I/O 来仿制数据,功能相对较低,后续的日志写入需求等待 flush 完结,这将影响咱们的写入功能,因而咱们考虑两种计划来提高 flush 速度以优化写入功能

  1. mmap 偏移映射,经过 mmap 映射归档文件的结尾,之后经过内存仿制将 mmap 缓存追加到归档文件结尾。这种方法将文件仿制变成内存仿制,功能较好。
  2. 文件重命名,关于可以快速上传并删去的日志,咱们可以在需求时将 mmap 缓存重命名成归档文件,之后重建缓存。这种方法直接去除了仿制的环节,但是在日志量较大时,或许产生很多琐细的归档文件。
货拉拉客户端通用日志组件 - Glog

这两种计划可以在咱们的不同日志场景运用,关于实时、监控日志来说,对功能要求最高,选用第 2 种计划,这个计划带来的琐细归档文件问题,因为上传和删去较快,在这里并不会堆积,另一方面,考虑到实时、监控日志上传周期较短,琐细的归档文件也便于操控上传的数据量;而离线日志选用第 1 种计划,可以将每天的日志归档在一个文件中,相对常见的规范 I/O 也有功能上的优势。

加密方法

Glog 运用了 ECDH + AES CFB-128,对每条日志进行单独加密。详细来说经过 ECDH 洽谈加密秘钥,之后 AES CFB-128 进行对称加密。

货拉拉客户端通用日志组件 - Glog

选择 CFB-128 是因为 AES 通用性和安全性较好,加解密只需执行相同块加密算法,对 IV 随机性要求低,ECC 相对 RSA 在加密强度相同的前提下,秘钥更短。

Security(In Bits) RSA Key Length Required(In Bits) ECC Key Length Required(In Bits)
80 1024 160-223
112 2048 224-255
128 3072 256-383
192 7680 384-511
256 15360 512+

紧缩方法

考虑到解紧缩的快捷性和通用性,Glog 运用了常见的 Deflate 无损紧缩算法,对日志进行流式紧缩,即以每条日志为紧缩单元,在每次写入时进行同步紧缩。这样避免了归档时对整个 mmap 缓存做紧缩带来的 CPU 波峰,详细的原理下面做一些解说。

Deflate 算法是 LZ77 与哈夫曼编码的组合

LZ77

LZ77 将数据(短语)经过前向缓冲区,然后移动到滑动窗口中成为字典的一部分,之后从字典中查找能与前向缓冲区匹配的最长短语,假如可以射中,则成为短语符号作为成果保存起来,不能射中则作为字符符号保存。 解压时,假如是字符符号则直接仿制到滑动窗口中,假如是短语符号则在滑动窗口中查找相应的偏移量,之后将滑动窗口中相应长度的短语仿制到成果中。

短语符号包含了

  1. 滑动窗口中的偏移量
  2. 匹配射中的字符长度
  3. 匹配完毕后前向缓冲区的第一个字符

下面展现了对字符 LABLALALABLA 进行 LZ77 紧缩和解紧缩的进程,

货拉拉客户端通用日志组件 - Glog

接下来霍夫曼编码对 LZ77 的处理成果(包含前面说到的偏移量、长度、字符),依照呈现频率越高,占用空间越少的方法进行编码存储。 在扼要阐明原理之后,咱们知道影响紧缩率的几个因素:滑动窗口(字典)巨细,输入的数据(短语)长度、以及短语中字符的重复率。字典越大、短语越长,越容易从字典中找到匹配短语从而变成短语符号,那么流式紧缩以每条日志作为紧缩单元,输入数据长度变短,咱们怎么确保紧缩率呢? 这里咱们能做的是尽量确保字典的巨细,不频频重置字典,详细做法是只在 mmap 缓存归档时重置字典,关于归档前 mmap 缓存的数据,复用字典来确保紧缩率。

音讯行列

mmap 相对规范 I/O 在功能上有较大优势,首要是因为其减少了内核空间与用户空间的仿制、以及 write lseek 体系调用带来的上下文切换开支

货拉拉客户端通用日志组件 - Glog

但在体系资源不足时 mmap 仍有或许呈现功能问题,举个例子,咱们知道 mmap 与规范 I/O 相同也需求经过 Page Cache 回写到磁盘

Page Cache 的生命周期: 当用户经过规范 I/O 从用户缓冲区向内核空间仿制数据时,假如内核缓冲区中没有这个 Page,将发生缺页中止分配一个 Page,之后仿制数据,完毕后这个 Page Cache 变成一个脏页,然后该脏页同步到磁盘中,同步完毕后,这个 Page Cache 变成 Clean Page 保存在体系中。

Android 中可以经过 showmap 指令调查 mmap 写入了 Page Cache

货拉拉客户端通用日志组件 - Glog

当体系内存不足时,体系将收回 Page Cache 来开释内存,引起频频的磁盘回写,mmap 功能也会受到影响。 另一方面因为实时日志、监控日志需求高频归档,而归档会堵塞后续的写入。因而咱们在 Glog 底层参加了音讯行列来处理写入和归档等操作,进一步提高功能,避免卡顿。

货拉拉客户端通用日志组件 - Glog

功能比照

手机类型 日志 SDK 1w 条日志耗时 10w 条日志耗时
Samsung Galaxy S10+ Android 11 glog 21 ms 182 ms
glog+pb 54 ms 335 ms
xlog 207 ms 1961 ms
logan 250 ms 6469 ms
Huawei Honor Magic 2 Android 10 glog 38 ms 286 ms
glog+pb 84 ms 505 ms
xlog 263 ms 2165 ms
logan 242 ms 3643 ms
Xiaomi 10 Android 11 glog 27 ms 244 ms
xlog 198 ms 1863 ms
logan 210 ms 4238 ms
Huawei Mate 40 pro HarmonyOS 2.0.0 glog 30 ms 257 ms
xlog 275 ms 2484 ms
logan 260 ms 4020 ms
OPPO R11 Android 8.1.0 glog 63 ms 324 ms
glog+pb 234 ms 1611 ms
xlog 464 ms 3625 ms
logan 430 ms 5355 ms
iPhone 12 128G iOS 14.8 glog 7 ms 29 ms
xlog 152 ms 1079 ms
logan 162 ms 12821 ms
iPhone 8 64G iOS 13.7 glog 12 ms 50 ms
xlog 242 ms 2106 ms
logan 251 ms 38312 ms

Glog 运用异步形式、按天归档

经过比照数据来看,Glog 异步形式因为运用了音讯行列,即便累加上 Protobuf 的序列化时间,写入功能相对来说依然有较大优势。

遇到的问题

  • 运用 mmap 偏移映射方法仿制数据时,需求经过 mmap 映射文件结尾,其偏移量也需求是 page size 的整数倍,而归档文件和仿制数据巨细一般情况下都不是 page size 的整数倍,需求做额定的计算;
  • 假如只对归档文件总体积作为阈值来清理,在重命名归档这种情况下琐细文件较多,或许在搜集文件列表的进程中导致 JNI 本地引用超限,需求约束文件总个数、及时收回 JNI 本地引用;
  • 在跨天写入日志的情况下,mmap 缓存中的数据或许无法及时归档,形成部分日志误写入次日的归档文件当中,需求在归档轮询中增加时间窗口的判定;
  • 为了便于上层上传日志,在底层需求增加日志解析模块。

总结

经过上面的介绍,可以看到 Glog 相较其他盛行计划的首要区别是:

  • 存储的是格局无关的二进制数据,具有更好的定制性;
  • 底层完成的音讯行列,功能更优运用也更方便;
  • 新的归档方法一方面提高功能,另一方面也便于高频读取。

当然这些手段也带来了一些妥协,比方因为存储的是二进制数据,运用 Glog 需求额定增加序列化代码;异步形式下,音讯行列中的使命在 Crash 或断电时或许丢失,这些问题在咱们的运用场景根本可以疏忽。 为了完成货拉拉的事务需求,咱们参考盛行的日志计划,站在伟人的膀子上,在移动端存储组件高功能、牢靠、安全的根本要求之外,供给了更多的特性和额定的优化。在开源之后,也期望可以反哺社区,为移动开发者供给一种更为通用的日志计划。

以 Glog 为存储模块的日志体系,现在现已接入了公司的全线 app,实时日志的单日日志量达到数十亿条,安稳运行在百万等级的 App 上。为线上用户反应问题解决、App 崩溃排查供给了有力的帮助,除此之外,还为风控体系、监控大盘供给了数据支撑。

货拉拉客户端通用日志组件 - Glog