__java
之家经销商业务迅猛发展,技术团队日益壮大,系统的数量和复杂度快速上升,从3年前的20人到如今170人的技术团队。在对业务提供支持的过程当中,咱们本身面临了很多的问题,主要痛点以下:nginx
之前问题反馈的路径是:端用户反馈给顾问,顾问找产品确认,产品找开发和测试。这条反馈路径至关长而且低效。
通常来讲,当顾问收到用户反馈的时候,形成的影响面已经不小了,这中间还有信息流转,沟通不顺畅等问题,根本没法作到先于用户发现问题。git
大量的文本和不合理的日志记录,不只没有带来效率提高,反而是一个阻碍,从几百兆的文本日志里查找关键错误信息,对任何人都是一个很大的挑战,更别说效率了。因此基本是靠回忆上线改动,而后猜想验证,中间还有反复的过程,对开发来讲,也是至关痛苦。github
在之前,你若是问开发同事,大家接口的性能咋样,平均耗时,tp99是多少,一天有多少个500错误,耗时大于500ms的请求一天有多少个,开发同事只能用绝望的眼神告诉你:不知道。web
没有系统指标统计和监控,每每让开发感受平静的表面下暗藏各类问题,不知道何时爆发。问题反馈到开发的时候,开发毫无准备,毫无安全感。spring
注意不是一条腿是半条腿。在咱们团队开始微服务选型的时候就已经意识到,没有系统全面的日志和监控,微服务带来的问题不会比收益小。sql
相信这些问题,每一个开发团队多少都会有共鸣。数据库
_tomcat
解决这些痛点的办法,一套好用的日志系统是一个很天然的解决方案。以前,日志的利用率简直低到可怕,线上产生大量的文本日志,根本无人问津,要想从这些日志里挖掘关键的信息,你须要会不少高级技能和一些黑科技工具,让不少开发同事望而生畏。因此首先要挖掘日志这座金矿,提升日志利用效率。日志系统能解决排查问题低效的问题,可是要解决其余几个痛点,还须要配套的日志监控系统。 安全
因此咱们最后的目标是:一套集日志收集,查询分析,监控报警于一体的日志系统。
__
易用性,灵活性,扩展性的权衡
日志系统做为一个产品,它的产品功能设计和体验相比技术更加剧要,并且技术同时也是产品,这对咱们作技术的人来讲才是更大的挑战,也是更大的乐趣所在。
问题1:kibana已经提供了强大灵活的日志分析功能,咱们是否须要再作一个本身的日志产品。
咱们的答案是须要的。灵活强大是kinaba的优势,同时也是弱点,由于对于不少长期业务开发的同事来讲,kibana,elasticsearch,lucene查询语法的学习成本并不算低,最主要的是平时你们使用的查询都是相对很简单的,分析模式也相对固定,一个web页面的form表单,几个简单操做就能完成90%以上的需求,易用性高于kibana不少,并非kibana很差,只是在咱们这种场景下,咱们更看重易用性,没有绝对好与很差,只有是否是适合。
问题2: 已经有了开源的或收费的日志系统,咱们是否须要作一个本身的日志产品。
在已经有了开源的日志方案(表明为点评的CAT系统),也有以日志易为表明的收费Saas日志服务的状况下,咱们选择本身开发一套日志系统的主要缘由是功能的可扩展性考虑。
在刚开始日志需求较为初级的时候,现有的方案基本都能知足需求,可是做为一个内部日志系统,咱们预见个性化的定制需求会层出不穷,因此轻量和功能的可扩展性咱们尤为重视,在这样的权衡场景里,咱们本身开发的日志系统在轻量,可控性,可扩展性方面,是现成的方案是没法比拟的。事实也证实,咱们的考虑是对的,后面不少很重要的定制化的需求里,若是是基于现有解决方案基本是没法实现的。
另外关于日志Saas服务还有一个很难克服的困难就是日志数据自己是很重要,保密性较高的数据,通常来讲,很难让公司放心的存入别人的数据库。
因此在选型里太重和灵活性一般是被舍弃的部分,咱们更偏重易用性和扩展性。这一准则也贯穿了咱们本身在作日志系统的时候整个过程。
_
目前日平均收集访问日志40亿,程序日志10+亿,程序慢日志300W,日均UV 110,是部门整个开发团队(包括测试)大半的人数。监控数量达到1000+,日均运行38万次检测。 从收到的反馈和效果来看,基本解决了前面提到的痛点。
目前监控系统已经部分开源,详细请查看github地址: frostmourne(霜之哀伤)
_
咱们将日志分为以下几类:
程序日志能够说是最为重要的日志,使用log4j, nlog等日志框架记录程序里一些重要事件(异常的捕获,业务逻辑的异常等)的发生。程序日志都是开发人员通过思考人工埋的记录,在全部日志类型里含金量最高,这些记录在监控,排查问题中的做用举足轻重。
http服务调用记录。常见的如:nginx日志,iis日志,tomcat访问日志等。从访问日志里,咱们能够获得服务流量,整体性能,错误占比等这些很是重要的HTTP服务指标。在排查问题中一样占有重要的位置。
程序慢日志这个概念,先解释一下,类比数据库的sql慢日志,程序些慢日志就是记下那些执行耗时较长的方法和上下文信息,便于排查一些程序的性能问题。
APM系统大多基于调用追踪日志来实现,比较知名的如:zipkin,skywalking, pinpoint等,这些APM系统的实现原型基本都是来自google发表的Dapper论文。咱们部门目前使用的是skywalking。
咱们认为调用追踪日志只有在服务数量和复杂程度到至关大的体量的时候,才显得比较重要,另外须要整个公司用一套解决方案,造成较完整的调用链条才能发挥最大做用,并且有前面提到的比较成熟的单独开源解决方案,因此在自研里它的优先级最低。
_
技术价值最终都是须要经过产品来实现。最后咱们的日志系统具有的主要功能(并不是全部)以下:
用于查询各类日志的明细数据。能够根据全部字段进行过滤,很是方便强大。
能够针对项目分析,哪些方法执行超过阈值次数最多,方法耗时各区间数量的分布。
用于分析特定域名或url的性能。包括tp统计,耗时区间分布统计。
用于分析特定域名下各url状态码异常的数量。
用于分析某域名下哪些url耗时较长。
包括每一个域名天天的pv, 500, 404, 503, 504, 平均耗时, TP90, TP95, TP99, TP99.9数据。日报邮件以下图:
邮件将这些指标和昨天和上周指标作对比,波动幅度比较大的用红色标记,提醒接收人注意有可能存在变坏的风险。目前经过邮件提醒已经帮助同事提早发现若干次慢性问题。
结合静态代码指标(单测覆盖率,代码复杂度,代码质量分)和动态运行指标(流量,性能,可用性)综合评价全部站点,作一个排名,利于内部互相比较,了解本身站点各方面和别人比处于一个什么样的位置。
做为日志系统,日志的查询和分析只能达到50%的完成度,另外的一半就是监控报警。
开源的日志监控相关产品基本都是针对指标类时序数据的主机监控,好比:zabbix,open-falcon, Prometheus等。针对业务文档类数据的日志监控的项目基本没有,只有ElasAlert还算可用,在使用了一段时间以后,面临不少棘手的问题:死板的调度策略(只能统一每隔x分钟,全部监控调度一次,常常不知道堵在哪一个监控),报警内容没法作灵活定制,配置文件管理困难,后面咱们的配置文件数量达到200左右,一个配置文件配置不当,进程挂掉或阻塞,最后效果能够说很不理想。在经历这些过程后,咱们决定自研一套监控系统。耗时1我的月上线运行。
主要功能有程序日志监控,访问日志监控,慢日志监控,http调用监控,metric监控。目前运行监控数量近800个,基本线上有问题,开发同事分钟级别就能收到报警。
不管是从使用者的反馈和运行状况来看,效果仍是很理想的。下面是一张咱们监控配置的页面截图:
下面是咱们监控产生的钉钉报警内容的截图:
目前实现了部门之间日志隔离。
在监控建设完成后,咱们的日志产品基础核心功能基本完备,除了本身的功能设计以外,有不少功能是来自使用系统的同事的反馈
目前监控系统已经部分开源,详细请查看github地址: frostmourne(霜之哀伤)
_
结构图左右分开看,左半图是日志采集过程,右半图是日志存储和使用的过程。左半图从上往下看,右半图从下往上看。
_
日志系统第一个要设计的点就是要统一日志格式,包括程序日志,web访问日志。由于日志格式若是不统一,后面采集,存储和数据接口开发的复杂度成倍数增长。尤为在多语言环境的团队,日志格式不统一的太常见了。因此在开始作日志系统之初,咱们就设计了程序日志的格式,包含了23个字段,能够说是很是全了。web访问日志由于最开始收集的是iis日志,
因此就沿用了iis日志的标准。日志格式统一的实现依赖现有日志类库良好的扩展性,咱们在log4j, nlog基础之上很容易作到了扩展,实现了日志格式的统一。
这些日志扩展已经开源,详细请看github地址: autolog4j
_
目前支持两种日志采集方式:
在主机上安装agent程序,独立运行采集应用写的文本日志发送至服务器监听端口。咱们选用的是nxlog,nxlog在资源占用低,稳定性,日志发送速度这些方面都表现得很好。目前承担了所有程序日志,所有iis日志和大量nginx日志的发送任务,一直比较稳定。有一个小限制就是一条日志的长度,社区版本有限制,会致使过长的程序日志没法发送,可是这种日志不多。
随应用部署到服务器上,在应用进程内运行采集日志直接走网络发送至服务端。咱们直接采用大数据部门提供的log4j-appender扩展组件集成到java应用里。目前这种方式也很稳定,承担了java应用访问日志的绝大部分采集,中间只出过一个问题,
关于两种方式的优缺点,作一个对比矩阵:
采集方式 | 优势 | 缺点 |
---|---|---|
host-agent | 可靠性较高, 无代码入侵 | 每一个服务器都须要单独安装和配置,成本相对较高 |
process-agent | 接入基本没成本,接入方便 | 有入侵,可靠性不如host-agent方式 |
程序日志现成大量文本日志,天然而然的选择了host-agent的方式。当时主要的问题仍是日志格式不统一的问题。为了保证日志质量和下降接入成本,咱们能够经过扩展示有的开源日志类库定制特定的组件,具体来说,
咱们针对log4j1, log4j2扩展了本身的layout, 针对nlog-2.0扩展了LayoutExtension;
程序日志记录文本而后走网络发送还有一个额外的好处是起到冗余备份的做用,由于日志直接网络发送的话,谁也没法保证100%的可靠,记录了文本就能够防止一些关键日志发送失败没法查找的问题。虽然这种状况不多。
目前程序日志平均天天采集数量达1.9亿,磁盘占用约140G。
和程序日志相比,访问日志状况要复杂得多,由于webserver种类不一,通常至少有iis,tomcat,nginx三种,并且格式没法统一。
iis和nginx日志咱们采用host-agent方式,由于这两种都已经有大量可用的文本日志,只须要处理格式不统一的问题,要想iis和nginx打出同样格式的日志是不现实的,可是咱们能够分别为iis日志和nginx日志制定统一的标准,而后在这标准之上处理为统一个访问日志,这样成本就不会很高。
公司java应用几乎都是tomcat应用,可是tomcat开启访问日志对应用性能影响很大,因此通常咱们都会选择关闭tomcat日志,这样一来tomcat记文本这条路是不通了,这也是为何把它和iis,nginx区分的缘由。咱们的解决办法是开发一个springmvc的filter拦截请求,记下日志,而后经过process-agent走网络发送出去。
目前访问日志平均天天采集数量达14亿,磁盘占用约420G
程序慢日志是经过AOP的around拦截方式,记下目标方法的执行耗时,当耗时大于设定的阈值时,打一条慢日志。发送方式采用process-agent,考虑到程序慢日志原本就是一种采样的采集,对可靠性要求并无那么严格,并且接入方即是咱们很是看重的一个点,方便接入才方便推广给你们使用。nxlog配置虽然有样本模板,也并不复杂,可是对于没接触过的同事来讲仍是有些犯怵致使一些理解上的障碍。
_
在日志系统无到有的过程当中,日志的增加速度是很快的,接收端就会面临水平扩展对客户端无感知的问题,这里经过对客户端暴露域名,使用lvs作负载均衡,后面展机器只须要增长域名解析的方式实现。
logstash咱们也有在用,logstash的优势是自带数据处理管道,对一些较为简单数据转换清洗来讲很方便,而flume若是要作清洗,就须要写java代码,打包上传而后修改flume配置文件,相对麻烦许多,可是和flume相比来讲,logstash对资源的占用要高不少,在咱们的场景只须要简单的接收和写入kafka,并不须要清洗和转换,因此这块选择了flume。
_
在日志发送速度很大的状况下,日志存储数据库Elasticsearch就会随时面临高写入的挑战,因此中间引入了高吞吐,适合大数据场景的kafka队列作中间缓冲。另外当elasticsearch集群不可用时,能够保证日志收集不受影响,提升系统总体的可用性也是很重要的一方面。总的来讲,引入kafka能够保证日志接收端不会成为一个瓶颈,进而保证对各个发送端不形成坏影响。
_
日志的消费和写入使用高性能实时计算框架-Storm来作,事实上spark和storm都能很好的完成这部分工做;咱们选择storm的缘由很简单。公司恰好提供了Storm集群的资源和专门的运维团队,咱们在使用storm也有必定的积累。 在写计算任务的时候,面临的一个问题是,一次处理一条日志而后写入Elasticsearch这种简单处理方式吞吐量不够,解决思路是写操做合并,每接收100条日志写入一次Elasticsearch吞吐大大提升。
另一个问题是elasticsearch索引默认的refresh时间间隔是1s,在大量日志场景,1s刷新会形成很大的资源浪费,会有不少小段生成,对集群压力很大,因此这里调整了日志索引的刷新时间为5s,相对会好不少。
__
在收集大量日志后,通常来讲磁盘空间会成为一个瓶颈,虽然elasticsearch默认是有数据压缩的,可是是作了压缩比率和查询性能的平衡,压缩率并非最高,可是日志场景,查询性能一般并不会成为困扰的问题,因此很适合把数据压缩作到最高,把索引的codec配置为best_compression,通过对比能省出大约20%的空间。
elasticsearch集群能管理的数据并非无限的,主要受两方面的制约,磁盘空间和elasticsearch集群管理的分片数量是有上限的,超过这个限制,集群就会出现很不稳定的问题。好在日志数据做为一种时序数据,它的主要价值都在最近时间段的数据里,历史数据价值就小不少,因此很是适合rotate close clear。一般保留最近一个月甚至能够更少的数据就足够了。
另外就是日志存储字段类型的考虑,主要是字段是否须要分词,是否须要全文检索。每一个字段都要考量真实应用状况来决定。不须要分词的用keyword类型;关闭norm,日志场景一般不须要文档得分计算,更可能是按时间排序便可。
日志到达必定量还须要考虑分索引存储的问题,单个索引存储的文档也不是无限的,分索引有两种方法:
咱们选择第二种方法,缘由是第一种方法在提供查询服务的时候,能查询的时间范围确定要小不少,由于查询时间范围越大,须要查询的分片数目越大,举个最经常使用的访问日志查询案例:查询域名www.autohome.com.cn昨天的访问日志,方法一要查询24 * shard_count数量的分片, 而域名所属的部门是肯定,咱们就只须要查询对应部门的索引只须要查: 1 * shard_count数量的分片,固然查询效率要高不少。
__
系统结构图右半部分能够看到,咱们在elasticsearch之上作了数据接口,供日志后台和监控调用,还有一个独立的监控任务调度中心负责监控的调度。关于这部分和日志相关技术自己干系并不大,因此不在这里作更多的说明。
关于咱们的日志系统主要的点就是这些,做为一个总体的系统仍是有不少的细节没法一一说明,若是针对某个点想了解更多细节欢迎联系咱们团队。
__
在需求很迫切的时候,你们须要的并非大而全的系统,极可能是一些很基础的功能,识别这类需求快速上线是很是重要的。因此咱们最早作的是统一程序日志格式,收集和查询页面。这样你们开始熟悉咱们的产品并快速反馈。原型有了以后后面有许多的需求要作,这时候须要识别需求的轻重缓急,快速迭代出那些性价比高的需求,一些耗时较长,使用率低的优先级下降。
用户提出的需求虽然每每很粗糙,太细小或模糊不清,可是认真的思考用户诉求本质是什么,结合产品每每会产生很酷的点子。
举个例子,在有了不少的日志数据以后,有小伙伴提出利用咱们的日志数据提供一个业务系统质量评估,咱们以为这个想法很好,进行了进一步分析,获得各个业务的综合排名,让你们看到自身系统和兄弟系统之间存在哪些差距,对差距作出改进,进而造成良性循环
不管是产品设计和仍是技术设计,它的范围不少时候很是宽泛,设计不足不利于进化,设计过分带来的复杂度一样不利于迭代,甚至过犹不及。咱们的经验是小团队内部充分讨论,肯定进化的方向,在保证能够进化的前提下,能最快上线的设计咱们认为就是刚恰好的设计。这样的设计每每也比较简洁易用。