京东App秒级百G日志传输存储架构设计与实战

背景在日常工作中 , 我们通常需要存储一些日志 , 譬如用户请求的出入参、系统运行时打印的一些info、error之类的日志 , 从而对系统在运行时出现的问题有排查的依据 。
日志存储和检索是个很常见且简单的工作 , 市面也有很多关于日志搜集、存储、检索的框架可供使用 。
譬如我们只有个位数机器时 , 可以通过登录服务器 , 查看log4j之类的框架打印到本地文件的日志 。当日志多起来后 , 可以用elk三剑客处理日志 。
当日志量进一步增多 , 我们可以上消息队列 , 譬如kafka之类来承接 , 然后消费入库 。或者写本地文件 , 再采用filebeat之类上报再入库 。
以上都是较为常见的日志传输和存储的方案 , 成本可控的情况下 , 可适用于绝大多数场景 。
我们可以简单总结一下日志框架的功能 , 大概是暂存、传输、入库保存、快速检索 。
量级上升 , 成本高昂技术方案的设计和取舍 , 往往强受限于成本 。当成本高企到难以承受时 , 将必须导致技术方案的升级换代 。那么问题来了 , 我就是存个日志而已 , 怎么就成本难以承受了呢?
我们以一个常见的日志传输及存储方案来举例 , 入下图 , 暂存就是采用客户端写本地文件存日志 , 传输即是采用MQ , 消费入库常见的如ES 。下图方案 , 为了减少部分存储成本 , 将日志详情存储于压缩更好的Hbase , 仅将查询时需要的一些索引字段放在了ES 。

京东App秒级百G日志传输存储架构设计与实战

文章插图
 
以上作为一个常用的方案 , 为什么会成本高昂呢 。
我们来简单计算一下 , 京东App某个模块(是一个模块 , 非整个App累计) , 单次用户请求 , 用户的入参+返回值+流程中打印的日志占用的大小在40k-2M之间 , 中位数在60k左右 。该模块日常每秒约2-5万次访问 , 高峰时会翻10倍 , 极高峰可达百万 。
以3万每秒来算 , 产生的日志大小为1.8G , 也就是说即便是低负载时 , 这个日志框架要吞下1.8G的传输与存储 。但这是远远不够的 , 因为我们即便放弃极高峰 , 仅仅支撑偶现的高峰 , 也需要该系统能支撑秒级15G以上的吞吐 。但是这仅仅才是一个模块而已 , 算上前中台这样的模块还有很多 。
那么我们就可以来算一算了 , 一秒1.5G , 一个小时就是5.4TB 。小高峰是肯定要支撑的 , 也就是秒级30万是要保的 , 那么我们的系统就要能支撑秒级15G单模块 , 算上各模块 , 200G秒级是跑不了了 。
这只是各个机器所打印在各自本地的原始日志文件占用的大小 , 然后要发到MQ集群 , 大家都知道 , MQ也是写磁盘的 , 这200G一点不少的在MQ机器上做了保存 , 并且MQ还有备份机制 , 就以最简陋的单备份来说 , MQ每秒要承接400G的磁盘 , 并且离删除后释放磁盘还有挺长一段时间 , 哪怕只存1个小时 , 也是一个巨大的数字 。
我们知道 , 一般服务器在磁盘还不错的情况下 , 单机秒级写入量200多M算比较不错的情况 , 通过上面的了解 , 我们仅仅做到日志的暂存和传输就需要2千台以上的服务器资源 。
然后就到了worker消费集群 , 该集群只是纯粹的内存数据交换 , 不占磁盘 , worker消费后写入数据库 。大家基本可以想象到 , 数据库的占用是如何 。OK , 我们终于把数据存了进去 , 查询问题就成了另外一个必须面对的事情 , 如何快速从无数亿中找到你要查询的那个用户的链路日志 。
到了此时 , 成本就成了非常要命的事情 , 尤其方案的设计 , 会导致原本就很庞大的数据 , 在链路上再次放大多倍 , 那么巨大的硬件成本如何解决 。
缩短流程 , 缩减流量通过上面的分析 , 我们已经发现 , 即便是市面上最通用的日志方案 , 在如此巨大的流量面前 , 也难以持续下去 , 高昂的硬件成本 , 将迫使我们去寻找更合适的技术方案 。


推荐阅读