作者:货拉拉技术  链接:https://juejin.cn/post/7168662263337861133

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 的常见使用流程来看其覆盖的关键节点

另外,之前的日志系统只能通过下发任务回捞,实时性较差,还存在 I/O 性能等问题。

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

另一方面,为了提升日志的实时性,我们增加了实时日志,通过短轮询来进行定时上报,此外还补充了监控日志来支撑 App 的横向数据对比、评估 App 的性能指标,最终的方案如下

系统主要组成包括

  • Android/iOS 上层日志采集 SDK

  • 跨平台的储存组件 Glog

  • 负责日志存储过滤的日志后端

  • 负责日志展示的日志前端

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

  • 实时日志,快速上传,信息精简,能够接近实时的查看,快速定位、排查用户反馈的问题;

  • 离线日志,通过后台任务触发上传,按天归档,作为实时日志的兜底,要求信息完整详尽;

  • 监控日志,支持采样,作为监控大盘的信息源,实时性要求最高,日志只包括监控信息。

为了适配不同日志的存储格式,我们希望存储组件能够在格式上尽量通用,最好做到格式无关;另一方面我们也希望其性能、可靠和安全方面能够对齐一线水平,在调研了市面上流行的日志组件后,我们发现并没有现成方案满足我们的需求,因此我们自研了自己的日志存储组件 Glog。

方案概览

应用上层对不同类型的日志序列化(推荐 Protobuf)之后,将二进制数据存储到 Glog,对于上传频次较高的实时日志和监控日志,采用重命名缓存的方式快速归档;对于信息较全而上传频次不高的离线日志,我们采用 mmap 偏移映射的方式归档,相较标准 I/O 复制归档的方式,提升了性能。在可靠性和安全性方面我们也借鉴了当前的流行方案,例如 mmap I/O 提升性能和可靠性、流式的加密和压缩防止 CPU 突发峰值,另外我们在日志中加入了同步标记支持读取容错。

存储方式

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

具体的文件格式:使用 2 个字节描述每条日志长度,在每条日志末尾加入一个同步标志,用于文件损坏时的读取容错。

归档方式

回顾一下常见的日志组件中 mmap 的使用方式,首先 mmap I/O 需要映射一片大小为 page size (通常为 4KB) 整数倍大小的缓存,随着数据的写入将这片空间耗尽后,我们无法持续扩展这片空间的大小(由于它占用的是 App 的运行内存空间),因此需要将其中的数据归档,常见的方式是将其中内容 flush 追加到另一个归档文件当中,之后再清空 mmap 缓存,这个 flush 的过程一般使用标准 I/O

而我们的实时、监控日志为了快速上传保证数据实时性,采用间隔较短的轮询来触发 flush 并上传,这将导致 flush 频率变得很高;而通常的 flush 方式采用标准 I/O 来复制数据,性能相对较低,后续的日志写入需要等待 flush 完成,这将影响我们的写入性能,因此我们考虑两种方案来提升 flush 速度以优化写入性能

  1. mmap 偏移映射,通过 mmap 映射归档文件的末尾,之后通过内存拷贝将 mmap 缓存追加到归档文件末尾。这种方式将文件复制变成内存复制,性能较好。

  2. 文件重命名,对于可以快速上传并删除的日志,我们可以在需要时将 mmap 缓存重命名成归档文件,之后重建缓存。这种方式直接去除了复制的环节,但是在日志量较大时,可能产生很多零碎的归档文件。

这两种方案可以在我们的不同日志场景应用,对于实时、监控日志来说,对性能要求最高,选用第 2 种方案,这个方案带来的零碎归档文件问题,由于上传和删除较快,在这里并不会堆积,另一方面,考虑到实时、监控日志上传周期较短,零碎的归档文件也便于控制上传的数据量;而离线日志选用第 1 种方案,可以将每天的日志归档在一个文件中,相对常见的标准 I/O 也有性能上的优势。

加密方式

Glog 使用了 ECDH + AES CFB-128,对每条日志进行单独加密。具体来说通过 ECDH 协商加密秘钥,之后 AES CFB-128 进行对称加密。

选择 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 压缩和解压缩的过程,

接下来霍夫曼编码对 LZ77 的处理结果(包括前面提到的偏移量、长度、字符),按照出现频率越高,占用空间越少的方式进行编码存储。在简要说明原理之后,我们知道影响压缩率的几个因素:滑动窗口(字典)大小,输入的数据(短语)长度、以及短语中字符的重复率。字典越大、短语越长,越容易从字典中找到匹配短语进而变成短语标记,那么流式压缩以每条日志作为压缩单元,输入数据长度变短,我们如何保证压缩率呢?这里我们能做的是尽量保证字典的大小,不频繁重置字典,具体做法是只在 mmap 缓存归档时重置字典,对于归档前 mmap 缓存的数据,复用字典来保证压缩率。

消息队列

mmap 相对标准 I/O 在性能上有较大优势,主要是由于其减少了内核空间与用户空间的拷贝、以及 write lseek 系统调用带来的上下文切换开销

但在系统资源不足时 mmap 仍有可能出现性能问题,举个例子,我们知道 mmap 与标准 I/O 一样也需要通过 Page Cache 回写到磁盘

Page Cache 的生命周期:当用户通过标准 I/O 从用户缓冲区向内核空间拷贝数据时,如果内核缓冲区中没有这个 Page,将发生缺页中断分配一个 Page,之后拷贝数据,结束后这个 Page Cache 变成一个脏页,然后该脏页同步到磁盘中,同步结束后,这个 Page Cache 变成 Clean Page 保存在系统中。

Android 中可以通过 showmap 命令观察 mmap 写入了 Page Cache

当系统内存不足时,系统将回收 Page Cache 来释放内存,引起频繁的磁盘回写,mmap 性能也会受到影响。另一方面由于实时日志、监控日志需要高频归档,而归档会阻塞后续的写入。因此我们在 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相关推荐

  1. Work Time Manager【开源项目】- 创建自己日志组件 2.0重构

    这次我们真是开始来聊聊开源项目里,小而有用的模块或者组件的开发思想. 同时,软件已经更新到1.60的版本了,支持新用户注册,可以不再使用统一的test账户了. 您可以通过以下路径进行下载: 1.在Gi ...

  2. 货拉拉携手神策数据,数据赋能企业,实现多元颠覆式创新

    近日,货拉拉签约神策数据,未来神策将以第三方数据分析平台的形式助力货拉拉进一步加快同城货运产品和服务的创新与突破. 货拉拉于 2013 年创始于香港,以平台模式连接车货两端,提供"互联网+& ...

  3. 堪称货拉拉混合云数据库建设史,一场DBA团队的逆袭之战

    本文根据蔡鹏老师在[2021 Gdevops全球敏捷运维峰会-广州站]现场演讲内容整理而成. (点击文末"阅读原文"可获取完整PPT) 讲师介绍 蔡鹏,前饿了么,蚂蚁金服技术专家, ...

  4. 2021年7月 虾皮、货拉拉、有赞等面经总结

    大家好,我是若川,加我微信 ruochuan12 进源码交流群.今天分享一篇7月份新鲜出炉的面经,文章较长,可以收藏再看.学习源码系列.面试.年度总结.JS基础系列. 本文来自作者@几米阳光 投稿 原 ...

  5. 货拉拉Android稳定性治理

    App Crash对于用户来讲是一种最糟糕的体验,它会导致流程中断.app口碑变差.app卸载.用户流失.订单流失等.相关数据显示,当Android App的崩溃率超过0.4%的时候,活跃用户有明显下 ...

  6. 两个组件连线_如何正确的使用日志组件 Log4j、SLF4J、Logback

    来源:http://t.cn/EVpprGI 相信目前大多数情况下,不管是开源框架或是平时工作编码中都离不开一种框架,它就是日志框架,本文了解一下我们常用日志框架的区别及如何正确的使用. 1.Comm ...

  7. Enterprise Library2.0研究(一)日志组件的使用场景

    Enterprise Library2.0刚刚发布了December 2005的release,多了configuration的工具,真是及时,就不用自己做了.被安排看日志这一块,就开始翻译官方的do ...

  8. 货拉拉 Android 动态资源管理系统原理与实践(上)

    点击上方蓝字关注我,知识会给你力量 ❝ jary,货拉拉高级客户端工程师,目前负责货拉拉App Android端稳定性提升,包体积优化相关工作. ❞ 前言 随着公司业务的扩展,货拉拉用户端apk包的体 ...

  9. 货拉拉 Android 动态资源管理系统原理与实践(下)

    点击上方蓝字关注我,知识会给你力量 so资源动态化方案 so资源打包问题 在打包so资源的过程中,我们遇到了如下问题. 如何移除apk中的so文件,并将他们收集起来? 如何将多个so文件压缩打包,并生 ...

最新文章

  1. 还在头秃自己的转录组数据怎么处理画图发文章,不如来看看这个
  2. 每年颁发两个图灵奖?
  3. 2021年,深度学习还有哪些未饱和、有潜力且处于上升期的研究方向?
  4. 信息系统项目管理师-项目立项管理考点笔记
  5. mysql一直拒绝登录_mysql 登录错误:1045 (28000)访问被拒问题
  6. Android之解决主页面Activity监听fragment退出问题(由NavHostFragment和RxFragment一起管理fragment)
  7. 第一节: 结合EF的本地缓存属性来介绍【EF增删改操作】的几种形式
  8. 《BERT:Pre-training of Deep Bidirectional Transformers for Language Understanding》
  9. ie 无法运行php,PHP会话无法在IE中运行
  10. duilib 子窗口位置_duilib各种布局的作用,相对布局与绝对布局的的意义与使用方法...
  11. cacti添加apache监控模板
  12. 4.数据中台 --- 数据中台建设的评估与选择
  13. 非线性光纤光学相关学习
  14. 手机连接hp打印机打印
  15. CSAPP 第三版 第六章 家庭作业and so on
  16. monocle安装不成功 想尽各种办法
  17. 教你创建qq好友桌面快捷方式
  18. 本题要求实现一个函数,输出n行空心的数字金字塔。
  19. linux 串口 数量限制,linux – 你的Unix的TTY主要数量是多少?
  20. Mavenir被以色列Partner选为下一代网络

热门文章

  1. Tableau数据分析笔记-Chapter06填充地图、多维地图、混合地图
  2. java节假日算法_java处理节假日和工作时间的工具类
  3. Jenkins集成GitLab Webhooks自动化构建
  4. Metasploitable2虚拟机镜像下载地址
  5. 未来简史--读书语句摘录及感悟
  6. 保存二维码图片到手机相册
  7. 微信表情《程序员小黄第二季》上架啦!
  8. 制作标准1寸和2寸照片方法
  9. win10千万不要重置_Win10系统如何自动恢复到出厂设置,小白式操作教程
  10. 360度全景效果图制作步骤是什么?