在过去的几年里推进公司容器云的落地,陆陆续续的和日志打了不少交道,在这里做一个总结:
日志的作用我觉得有三点:
1,关于故障排错,当线上发生异常,查看应用的错误日志、堆栈信息、代理层的访问日志是非常有帮助的,不同级别的日志能够很好的帮助我们定位到故障点,而访问日志则能让我们知道异常情况发生在哪个环节,是client到代理,还是代理到后端。这也是降低MTTD的一个很好的工具。
2,对日志数据的分析,一方面能协助分析问题、定位故障,另一方面还可以帮我们更好的了解系统运行状态甚至是了解我们的用户。比如基于HTTP状态码和响应时间可以分析出系统的稳定性和性能状况。而基于访问日志的来源IP可以分析出用户地域属性、而基于日志量级的时间分布可以了解到系统和用户的活跃时间范围。
3,上面两种多数是最近几个月的热数据,需要实时查看和分析,也有一部分需要保存的更久,以满足合规、审计等的需求。比如有些备案就要求不同级别的日志保存不同的时长以备随时调用查看。
在分布式系统中,众多服务分散部署在成百上千台甚至成千上万台服务器上,要想快速方便的实现上述的查找、分析和归档功能,就需要有一个集中的日志系统,通过日志收集器将各类日志进行统一汇总,存储,这样不仅能方便查找所有的日志,还有可能在众多日志数据中挖掘到一些意想不到的关联关系。
有了这个定位接下来就可以开始详细的规划了,首先是日志服务器的选型,有经典的ELK,有商业的splunk,但我们并没有采取上述两种,splunk功能完全符合,但对大量级的日志而言成本偏高,ELK中的kibana也在高版本中开始商业化,这让我们开始寻找替代方案,graylog便是一种。它的绝大多数功能都是免费的,并且性能优越,上图:
graylog也采用Elasticsearch作为存储和索引以保障性能,MongoDB用来存储少量的自身配置信息,master-node模式具有很好的扩展性,UI上自带的基础查询与分析功能比较实用且高效,支持LDAP、权限控制并有丰富的日志类型和标准(如syslog,GELF)并支持基于日志的报警。
在日志接收方面通常是网络传输,可以是TCP也可以是UDP,在实际生产环境量级较大多数采用UDP,也可以通过MQ来消费日志。
不同日志有不同的收集方式,总结下来有如下几种:
$ head /etc/rsyslog.conf
*.* @your-log-server-addr:port;RSYSLOG_SyslogProtocol23Format
$ docker --version
Docker version 1.12.0, build 8eab29e
修改配置文件/usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd --storage-driver=overlay --graph=/data/dockerapp \
--log-driver=gelf \
--log-opt gelf-address=udp://xxx.com:9999 \
--log-opt tag=docker \
--log-opt env=pro \
--log-opt gelf-compression-type=gzip \
--log-opt gelf-compression-level=1
kubernetes,如果是在公有云如Google Cloud上面的Stackdriver Logging
为统一管理,如今一般选择daemonset的方式部署日志收集器,对上述日志进行统一的收集。
Logstash功能强大,但性能消耗也大,相对比较重,更适合作为中间环节,elastic后来推出的Filebeat更适合,它的性能好且资源占用少。而Fluentd作为CNCF指定用品,在17年初用了一段时间,觉得性能不是很好,它基于磁盘或内存的buffer优化空间也非常有限,但随着加入CNCF后市场占比更多,也推出了Fluent-bit消耗1/10的资源。
这些收集器可以以daemonset的方式部署,确保每个节点上有且只有一个实例在收集日志。
上述只能实现日志的收集、存储和展示,但想要更好的分析,就需要用到日志标准化,对不同日志、不同类型做不同的管理。如为方便快速查找某个系统在过去一段时间的访问质量,对需要对代理层日志中的HTTP状态码做清晰明了的界定。
对于应用日志,一般通过内部封装好的包直接推广使用,如java的logback,golang通过封装zap等方式,集成如下通用字段:
为提高可扩展性,在应用日志和Nginx日志都采用json格式,这样就省去如logstash等组件的加工环节,同时也可基于json中的字段对日志做处理,如生产环境下logLevel=debug级别的日志不做处理,对size过大的做截断。
更新:随着单台节点上日志规模的增大,我们发现如果用filebeat进行json化日志收集存在较大的性能压力,还是需要增加一层logstash进行json日志的处理,filebeat回归到最基本的日志收集层面。
对访问日志,可添加的就更多了,如:
log-format-upstream: '{ "message":"$remote_addr $host $request_time $status", "remote_addr":
"$remote_addr", "domain_name": "$host", "remote_user": "$remote_user", "http_tracker_id":
"$http_tracker_id", "time_local": "$time_local", "request_proto":
"$server_protocol", "request_path": "$request_uri","request_args": "$args","response_status":"$status","request_time":"$request_time","body_bytes_sent":"$body_bytes_sent","request_length":"$request_length",
"http_referer":"$http_referer","http_user_agent": "$http_user_agent","upstream_addr":"$upstream_addr",
"upstream_connect_header_response_time":"$upstream_connect_time $upstream_header_time
$upstream_response_time","upstream_status":"$upstream_status","http_x_forwarded_for":
"$http_x_forwarded_for" }'
但注意,在日志量级较大的情况下如果字段设置过多会对日志收集器有一些性能压力。
graylog自身支持对日志的报警,如某个域名\应用在某个时间段内的错误日志数如果超过某个阈值就报警。报警渠道支持邮件和webhook,对接上我们的告警中心接口即可实现特定异常发送给特定人群。全局异常做基本分析后再发给特定人群和管理员,如:
graylog商业版自带归档功能,如果自己做可以通过消息队列将日志数据再存入到HDFS中一份。