继续聊CNCF(云原生计算基金会)下已毕业的16个技术项目。这一次要说到日志了。
在微服务架构中,日志是一个不得不面临与需要解决的点。因为微服务架构中,服务是分散在不同的节点或虚拟机上运行,这意味着服务产生的日志也是分散的,所以收集分散的日志就成为了微服务中的一个痛点。否则有需要时查询起日志来就非常麻烦与不方便。
当然,这个点的一些解决方案也是架构师们人所共知的,比如最著名的搭配就是ELK了,也就是elasticsearch,logstash以及kibana的组合。
简而言之,fluentd就是与ELK中的logstash作用一样的技术。它是一个日志收集器,通常在云原生架构中,会使用它来取代logstash,也就是EFK搭配了。
在本篇文章中,我将分为三个点来进行阐述:
- 1. fluentd日志收集器在架构中的作用
- 2. fluentd与logstash的区别,为什么云原生架构中主要是使用fluentd而不是logstash
- 3. 在Docker Swarm以及K8S这两种容器编排技术中,如何整合fluentd
一)
日志收集器是做什么的?
前文已经阐述过,微服务架构中,服务是分散的,所以日志也是分散的。日志收集器这名字非常容易理解,就是收集日志的。
一个日志收集器的核心作用就是:
- • 读取服务产生的日志
- • 过滤日志,转换格式,并进行适当的处理(如格式转换,添加更多的信息等)
- • 处理后的日志传输到日志存储,比如elasticsearch或OSS存储等
无论是logstash或是fluentd,都是干这些事的,功能上大致相同。
好,继续扩充这个点的思考,为什么需要日志收集器,而不是服务来做这些事?
主要是基于解耦与性能的考量,如果让应用服务自己来做这些事,第一影响日志产生及记录的性能,因为你可能需要写到一个elasticsearch服务中,比起写入文件或stdout中,显然降低了性能,增加了复杂度。第二,服务的日志耦合了很多其它点,这是非常不恰当的。
所以,从设计上来说,设计一个独立的日志收集器,让它单独来收集与处理日志,显然架构上是更合理。
二)
好,继续下一个话题,说一说fluentd与logstash这两个日志收集器吧。
首先,我们要知道,存储与分析日志数据的最有名的工具就是elasticsearch,elasticsearch能很好对文本进行分析与处理并提供搜索能力,而logstash也是同一个公司的搭配elasticsearch的工具,而kibana则是一个日志查询UI工具。基于elasticsearch的影响,使得ELK成为了微服务中日志处理的最有名的选择与搭配。
但在云原生架构中,fluentd是CNCF官方的项目,是更合适的选择。为什么呢?
说下这两个工具的一些区别。
容器编排工具(Docker Swarm / K8S )对fluentd的支持度更好
fluentd是CNCF的项目,而CNCF则是以K8S为核心的开源组织。理所当然的,无论是K8S,或是Docker Swarm这样的容器编排工具,都对fluentd提供了更好的支持与集成。
比如fluentd是Docker的几种日志驱动之一,是Docker自带的,而logstash则不再官方自带支持之内(当然会有第三方实现)。而在K8S官方文档中,介绍日志时,也提供了集成fluentd的示例说明,logstash则没有。
个中偏好,可见一斑。
性能
日志收集器这种工具,不得不考虑它的性能表现,毕竟需要一个独立的服务来不停的收集与处理日志,肯定是性能更好的更让人喜欢。
在这一点上,同样是fluentd占据了优势。fluentd是基于Ruby语言实现,而logstash则是基于JRuby写的。
别看Ruby与JRuby只差一个字母,JRuby本质上是基于JVM虚拟机的,其性能是差于Ruby的。而在实际的测试中也证明,fluentd的内存与资源的需求是小于logstash的。
存储队列不同
日志收集器,都会有一个队列。因为有时候日志过多,需要一个队列,对需要处理的日志进行存储以待处理。
而在这方面,fluentd表现更优,fluentd提供了内存及硬盘存储队列,无须第三方就能满足,而logstash本身只提供了20个事件队列,这个数额是严重不足的,所以通常logstash需要搭配一个第三方存储队列技术,比如Redis。
我曾经使用过logstash,当时是搭配了Redis来实现日志的缓冲,logstash收集器先把日志缓冲到Redis,而另一个logstash解析则从Redis中读取并处理。
这意味着,在使用logstash时,架构上你需要一个第三方缓冲技术来保障日志的不丢失。
事件路由规则
日志收集器都提供了事件路由的机制,所谓事件路由就是类似,如果是登录或登出日志,则如何处理
遇上这样的需求时,你就需要事件路由规则编写了。当然无论是logstash还是fluentd,都是支持这样的路由规则。
不同的是,logstash提供的是编程式的路由规则(if-else),而fluentd提供的则是声明式的路由规则。
当然,哪种更好,就见仁见智了。
插件机制不同
日志收集器都是支持插件的,比如如何写入elasticsearch,如何写入OSS存储等,都可以通过插件来实现。丰富的插件会让日志收集使用起来更容易与简单。
无论是logstash还是fluentd,都支持插件。当然主流的插件能力都有,无须担心。
不同的是,logstash是中心式的插件存储,所有插件都在GIthub一个仓库中,而fluentd则是分布式的插件,不同的插件的地址分散在不同的仓库中。
三)
最后说下Docker Stack/Swarm与K8S如何与fluentd搭配。
当然,得说明下,并不是说logstash就不能在这样的搭配中使用,也是可以的。只是fluentd从各方面来说,是这些容器编排工具更佳的选择。
而容器编排,我通常只关注两个,轻量级的Docker Stack/Swarm与企业级K8S,就以这两个来说明。当然,要注意,我在这里只是简述实现方式,非详细教程。
Docker Swarm fluentd
Docker本身提供了日志桥接驱动,默认Docker镜像日志是存储在文件中的,但Docerk官方提供了一些日志驱动,支持将容器镜像的日志写入这些第三方工具,
而fluentd则是Docker官方驱动的一种实现。
在Docker中配置fluentd非常简单,有两种方式。一种是默认值设置为fluentd驱动,另一种是为单独的服务设置fluentd驱动。
默认设置
docker配置文件 /etc/docker/daemon.json
代码语言:javascript复制{
"log-driver": "fluentd",
"log-opts": {
"fluentd-address": "fluentdhost:24224"
}
}
如上配置所示,配置Docker此计算机上所有服务默认使用fluentd,并指明了fluentd-address地址。
这样,除非服务自己额外指定了自己的日志驱动,否则所有日志会写入上述这个fluentd地址。
单独设置
当然,你也可以为容器服务指定自己特定的日志驱动。
代码语言:javascript复制docker run --log-driver=fluentd --log-opt fluentd-address=fluentdhost:24224
这样,这个容器服务,就是使用fluentd日志驱动了。
K8S fluentd
对于K8S来说,整合fluentd有两种方式,一种是以边车服务来实现,另一种则是以DaemonSet来实现。
以边车服务来整合
关于边车服务,我在前面的文章讲envoy时解释过了,它是在一个Pod中,主服务之外再部署一个从属的服务,比如网络代理envoy,日志收集fluentd等。
这种方式,相当于每个Pod都有自己的日志收集处理。这是一种实现方式。
以DaemonSet来整合
K8S的能力非常强大,对应的概念也非常多,DaemonSet就是其中一个。
DaemonSet是指针对每个K8S节点(Node)上都部署一个服务,(一个Node上可以有很多个Pod)。如果一个新的节点加入进来,DaemonSet服务会同时自动添加到这个节点上,而一个节点从K8S中移除,DaemonSet服务则会自动删除。
基于DaemonSet这样的概念,就非常适合做节点级的日志收集了。
基于DaemonSet来部署fluentd,意味着fluentd是对应节点上多个Pod,这些Pod的日志都在节点上并被节点的fluentd收集并处理。
显而易见,DaemonSet更高效。fluentd官方提供的建议就是DaemonSet这种方式了。
四)
对于微服务或以微服务为实现的云原生架构来说,对分散的日志的收集是必须的。而fluentd就是用来收集与处理日志的。
当然,需要进一步说明的两点是:
- 1. 在云原生架构中,你仍然可以使用logstash或其它技术,只不过fluentd是相对更合适的选择
- 2. 日志收集的存储输出是可以多种多样的,并非只有elasticsearch,收集与处理后的日志可以存储到elasticsearch中,当然也可以存储到数据库,文件或OSS任何方式都可以
现在,你应该大致了解fluentd是做什么的了吧。