背景
在日常工作中,我们通常需要存储一些日志,譬如用户请求的出入参、系统运行时打印的一些info、error之类的日志,从而对系统在运行时出现的问题有排查的依据。
日志存储和检索是个很常见且简单的工作,市面也有很多关于日志搜集、存储、检索的框架可供使用。
譬如我们只有个位数机器时,可以通过登录服务器,查看log4j之类的框架打印到本地文件的日志。当日志多起来后,可以用elk三剑客处理日志。
当日志量进一步增多,我们可以上消息队列,譬如kafka之类来承接,然后消费入库。或者写本地文件,再采用filebeat之类上报再入库。
以上都是较为常见的日志传输和存储的方案,成本可控的情况下,可适用于绝大多数场景。
我们可以简单总结一下日志框架的功能,大概是暂存、传输、入库保存、快速检索。
量级上升 成本高昂
技术方案的设计和取舍,往往强受限于成本。当成本高企到难以承受时,将必须导致技术方案的升级换代。那么问题来了,我就是存个日志而已,怎么就成本难以承受了呢?
我们以一个常见的日志传输及存储方案来举例,如下图,暂存就是采用客户端写本地文件存日志,传输即是采用MQ,消费入库常见的如ES。下图方案,为了减少部分存储成本,将日志详情存储于压缩更好的Hbase,仅将查询时需要的一些索引字段放在了ES。
以上作为一个常用的方案,为什么会成本高昂呢。
我们来简单计算一下,京东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,我们终于把数据存了进去,查询问题就成了另外一个必须面对的事情,如何快速从无数亿中找到你要查询的那个用户的链路日志。
到了此时,成本就成了非常要命的事情,尤其方案的设计,会导致原本就很庞大的数据,在链路上再次放大多倍,那么巨大的硬件成本如何解决。
缩短流程 缩减流量
通过上面的分析,我们已经发现,即便是市面上最通用的日志方案,在如此巨大的流量面前,也难以持续下去,高昂的硬件成本,将迫使我们去寻找更合适的技术方案。
世界上有一个著名的法则叫"奥卡姆剃刀定律",讲的是程序员该如何选择合适的剃刀,来让自己的秀发光滑柔顺有光泽。
其实不是的,该定律主要就是八个字"如无必要,勿增实体"。当一个流程难以支撑当前的业务时,我们就该审视一下,哪些步骤是不必要的。
从这个通用流程中,其实我们很容易就能发现,我们经历了很多读写,每次读写都伴随着磁盘的读写(包括MQ也是写磁盘的),和频繁的序列化反序列化,以及翻倍的网络IO。
那么让我们挥舞起奥卡姆的剃刀,做一些删减,把非必要的部分给删掉,就变成了下图的流程:
我们发现,其实写本地磁盘、和MQ都是没有必要的,我们完全可以将日志数据写到本地内存,然后搞个线程,定时通过UDP将日志直接发送到worker端即可。
worker接收到之后,解析一下,写入自己的内存队列,再起数个异步线程,批量将队列的数据写入ClickHouse数据库即可。
大家可能看到了,下图的流程中,那个圆圈明显比上图的圆圈要小,这是为什么呢?因为我做了压缩。
前文讲过,我们单条报文40k-2M,这是一个非常大的报文,这里面都是一些用户请求的入参Json和出参Json以及一些中途日志,我们完全没有必要将原文原封不动往外传输。
通过采用主流的snappy、zstd等压缩工具类,可以直接将字符串压缩成byte[]再往外传输,这个被压缩后的字符串,直至入库都是byte[],全程不对大报文解压。
那么这个压缩能压多少呢,80%-90%,一个60k的报文,往外送时就剩6-8k了,可想而知,仅仅压缩一下原始数据,就在整个流程中,节省了巨大的带宽,同时也大幅提升了worker的吞吐量。
这里有个小细节,udp单个最大报文是64kb,如果我们压缩后,还是超过了64kb的话,udp是送不出去的,这里可以选择发个http请求送到worker即可。
通过上图,我们可以看到,当流程中的某些环节并不是必需的时,我们应该果断砍掉,不要轻易照搬网上的方案,而应该选择更适合自己的方案。下面我们详细讲一下系统是如何设计、运转的。
更强悍的日志搜集系统
我们来审视一下这个链路极短的日志搜集系统。
配置中心:用来存储worker的IP地址,供客户端获取自己模块所分配的worker集群的ip。
client:客户端启动后,从配置中心拉取分配给自己这个模块的worker集群的IP,并轮询将搜集的日志压缩后发送过去,通过UDP的方式。
worker:每个模块会分配数量不等的worker机器,启动后上报自己的IP地址到配置中心。接受到客户端发来的日志后,解析相应的字段,批量写入clickhouse数据库。
clickhouse:一个强大的数据库,压缩比很高,写入性能极强,按天分片,查询速度佳。非常适合应用于日志系统这种写入极大,查询较少的系统。
dashboard:可视化界面,从clickhouse查询数据展示给用户,具有多条件多维度查询功能。
大家都能看出来,这其中最关键的地方是worker端,它的承接流量、消费性能、入库性能将决定着整个链路能否良好地运转。
我们主要分别讲解一下client端和worker端的实现。
Client端聚合日志
一次请求中,我们通常要保留的日志信息主要有:
(1)请求的出入参
如果是http web应用,要获取出入参比较简单的方式就是通过自定义filter即可。client的sdk里定义了一个filter,接入方通过配置该filter生效即可搜集到出入参。
如果是其他rpc应用非http请求的,也提供了对应的filter拦截器来获取出入参。
在获取到出入参后,sdk对其中大报文,主要是出参进行了压缩,并将整个数据定义为一个JAVA对象,做protobuf序列化,通过UDP方式往自己对应的worker集群轮询传输。
(2)链路上自己打印的一些关键信息,如调用其他系统的的出入参,自己打印的一些info、error信息
sdk分别提供了log4j、logback、log4j2三个常用日志框架的自定义appender,用户可以通过在自己的日志配置文件(如logback.xml)中,将我自定义的appender定义出来即可,那么后续用户在代码里所有打印的info、error等日志都会执行这个自定义appender。
同样,这个自定义appender也是将日志暂存内存,然后异步UDP外送到worker。
这里主要有两个地方需要注意,一是当压缩后的报文依旧超出udp最大报文值时,即通过http送出。二是这一次请求,链路中可能会使用多线程、线程池技术,为避免链路tracer的唯一id在线程池丢失,sdk采用了TransmittableThreadLocal来保持链路的ID,这个查一下就懂。
总体来说,client端实现较为简单,省略了写本地磁盘、消费文件发MQ等等步骤,整体只有一次Protobuf序列化操作,对CPU、接入方性能影响极小,采用UDP外送,不需要worker的任何回复,也不用考虑tcp模式下worker消费慢导致自己阻塞的问题。整体非常简洁高效。
Worker端消费日志并入库
worker端是调优的重点,由于要接收海量客户端发来的日志,解析后入库,所以worker需要具备很强的缓冲能力。
我们都能看出来,系统的瓶颈点肯定在入库这个阶段,解析日志,抽取字段都是效率很高的,而且完全可以通过控制线程的数量来控制住,而入库将强受限于clickhouse的写入性能。至于clickhouse是如何做的优化,后面会有clickhouse集群负责人来讲一下做了哪些优化。
为了做好这个缓冲,即便日志接收量大于入库量,我们也要能接下来这些数据,尽量不丢失。首先硬件上,采用大内存机器,8核32G的容器,来尽量多屯一些数据。其次,采用了双缓冲队列,先将所有接收的数据放一个队列,然后多线程消费、解析成可供入库的行数据,再放入一个待入库队列,然后批量入库。
那么我们做的这些操作,能支撑什么样的数据量呢?
通过线上的应用和严苛的压测,这样一台单机docker容器,每秒可以处理原始日志1-5千万行,譬如一条用户请求,中途产生了共计1千多行日志,那么这样的一台worker单机,每秒可以处理2万客户端QPS。对外写clickhouse数据库,每秒可以写160M-200M比较稳定。
通过对上文的了解,我们知道,这些数据都是被压缩过的,直至库里面的都是压缩过的,只有当最终用户查询时,才会进行解压。所以,这200M,基本相当于原始数据1G多的大小。
也就是说,只要clickhouse写入速度跟的上,这个系统仅需100台就可以极其高效地处理原始秒级百G的日志。对比写MQ的方案,中途所有会出现瓶颈的点如MQ写磁盘速度、消费拉取速度等,都将不复存在。这是一个纯内存交换的链路系统。
强悍的Clickhouse
通过以上的了解,我们可以清楚的看到,worker作为一个纯内存计算的组件,client端通过worker的数量进行hash均匀分发到各个worker,所以worker可以动态扩容而且不存在性能瓶颈,其唯一受限制的就是写入库的速度。
倘若写库速度跟不上,则worker必须要拿有限的内存去屯下发来的大量数据,一旦写满则就会开始丢弃接收到的数据。所以整个系统的瓶颈点,就是写库的速度。
Clickhouse是面向海量数据实时、多维分析、高性能的新一代OLAP数据库管理系统,实现了向量化执行和SIMD指令,对内存中的列式数据,一个batch调用一次SIMD指令,大幅缩短了计算耗时,带来数倍的性能提升。目前已成为驱动京东集团业务增长、创新的“超级引擎”。那么在京东App秒级百G日志传输存储架构中,Clickhouse如何支撑大吞吐量数据的写入,主要在于两点
1)集群高可用架构
EasyOLAP部署CH集群是三层结构:域名 + CHProxy + CH节点,域名转发请求到CHProxy,再由CHProxy根据集群节点状态来转发。CHProxy的引入是为了让Query均匀分布在每个节点上,,并对CHProxy做了一定的改进,自动感知集群节点的状态变化。
2)本地表写入
大吞吐量的数据写入分布式表时,分布式表会将接收的insert数据拆分成多个parts,并通过rand或者shard_key方式转发到各个分片,会引起ch节点网络带宽和merge的工作量增加,导致写入性能下降,并且会增加too many parts的风险和加大zookeeper的压力,另外数据会在分布式表所在节点进行临时落盘,然后异步的发送到本地表所在的节点进行物理存储,中间没有一致性校验,如果分布式表所在的节点出现故障,会存在数据丢失的风险。所以针对以上风险,大吞吐量的数据可直接写入本地表,相较于写入分布式表可以大幅度提升2-3倍的写入性能。
多条件查询控制台
控制台比较简单,主要就是做一些sql语句查询,做好clickhouse的高效查询,这里简单提一些知识点。
做好数据的分片,如按天分片。用好prewhere查询功能,可以带来性能的提升。做好索引字段的设计,譬如检索常用的时间、pin。
细节难以尽述,要从百亿千亿数据中,做好极速的查询,还需要对clickhouse的一些查询特性有所了解。
下图界面展示的即为一些索引项,点击查看详情,则从数据库捞出压缩过的数据,此时才解压并展示给前端。查看链路,则是该次请求中,整个链路用户打印的log(包括线程池内的)。
总结与对比
我们可以简单的做一些对比,主要在于硬件成本和软件性能的对比。
从上文可知,磁盘的占用原始方案占用了磁盘(1份),MQ(2份),数据库(1份)。而在新的方案中,磁盘的占用仅剩下clickhouse的(0.8份),clickhouse自身又对数据做了压缩,实际占用空间不到入库容量的80%。
那么仅磁盘即可节省75%以上的存储成本。
大家都知道,秒级的吞吐量,是伴随着服务器Cpu的耗费的,并不是说只给个大硬盘,即可一台服务器每秒吞吐1个G的。每台服务器秒级的吞吐量是有上限的,秒级占用磁盘的上升,即对应Cpu数量的上升,要支撑一秒1G的磁盘写入,需要5台或以上的服务器。
那么在磁盘的大幅节约下,线性地节省了大量的中间过程Cpu服务器。实际粗略统计效果,流程中服务器可节约70%以上。
在软件性能上,过程很好理解。对Client端的消耗主要就是序列化、写磁盘、读磁盘、反序列化这几步的消耗,Udp则仅有一步序列化。我们假设MQ集群是有无限的写入能力,可以吞下所有的发过去的日志,那么就是worker端的消费性能对比。
从MQ拉取并消费,这个过程如果MQ没有积压,则有零拷贝在支撑高速的拉取,如果积压了,则可能产生大量的MQ磁盘IO,拉取速度会大幅下降。这个过程效率会明显低于Udp发送到worker的处理效率,而且占用双份的网络带宽。实际表现上,worker表现出的强劲性能,较之前单条拉取MQ集群时,消费性能提升在10倍以上。
本文到此就结束了,主要简略介绍了一个新的日志搜集系统的设计方案,以及该方案能带来的巨大的成本节省。
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/o4yi-2U9JMCZTHaEAgFrow
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。