【技术干货】日志服务架构设计和实践

栏目: 后端 · 发布时间: 7年前

内容简介:9 月 16 日,以“云服务时代如何打造高可用的服务架构”为主题的“云片技术开放日”在上海市浦东区中兴智慧园举行,又拍云系统开发工程师张超受邀在活动上做了《又拍云日志服务架构设计和实践》的分享。张超,负责又拍云 CDN 平台相关组件的更新及维护。Github ID: tokers,热爱编程,活跃于 OpenResty 社区和 Nginx 邮件列表,曾为 ngx_lua 贡献源码,在 nginx 、nginx lua、CDN 性能优化、日志优化方面有较为深入的研究。平时混迹开源软件社区之中,专注于服务端技术

9 月 16 日,以“云服务时代如何打造高可用的服务架构”为主题的“云片技术开放日”在上海市浦东区中兴智慧园举行,又拍云系统开发工程师张超受邀在活动上做了《又拍云日志服务架构设计和实践》的分享。

【技术干货】日志服务架构设计和实践

张超,负责又拍云 CDN 平台相关组件的更新及维护。Github ID: tokers,热爱编程,活跃于 OpenResty 社区和 Nginx 邮件列表,曾为 ngx_lua 贡献源码,在 nginx 、nginx lua、CDN 性能优化、日志优化方面有较为深入的研究。平时混迹开源软件社区之中,专注于服务端技术的研究。

以下是分享全文:

又拍云作为一家 CDN 服务提供商,每天产生 50T 左右的日志,数量庞大、种类繁多,不论是公司内部,还是客户,对日志都有需求,而且需求都不尽相同。

所以,我首先谈一谈,为什么又拍云需要一个强大的日志系统,主要有三个原因:

首先是为用户提供日志归档的服务,日志根据不同的服务名可提供给用户下载,包括在又拍云后台上可以看到的服务,比如用户想了解自己的服务今天访问最热门的是哪些资源等。

其次是提供近乎实时、多维度的日志分析,包括问题排查,并对接到内部报警系统,这点对又拍云平台的稳定性来说非常重要,比如某个用户的源站网络出现问题,我们可以通过监控系统和内部的服务,将日志给到报警系统实现报警,从而可以通知用户。

第三是日志离线分析功能,可以进行复杂的数据模型计算分析,提供包括细化到每一个省份、城市,定期生成的报表,用户可以了解自己的服务在各个城市的访问情况。

日志服务系统概览

【技术干货】日志服务架构设计和实践

又拍云的日志都是通过 CDN 边缘节点的服务产生,服务基于 ngx_lua。ngx_lua 是 OpenResty 的一个核心组件,它将 Lua VM 嵌入到 Nginx 当中,极大地扩展了 Nginx 的能力。

这里介绍一下又拍云 CDN 代理层的服务全部是基于 OpenResty / Nginx 开发的,我们在 Nginx 的优化和二次开发方面投入了大量的精力。

这些日志在边缘节点进行一定的缓冲后,通过公网上传到数据中心的日志服务代理层。因为 CDN 节点分布在全国和海外一些地区,如果每一个机房都到数据中心建传输网络,这个成本比较大,所以这里都是走公网传输。

数据中心日志代理这层使用的是基于 OpenResty / Nginx 构建的一个服务,这层主要是由 LVS 进行四层的负载均衡,所有日志都会均摊到这个集群中的每台机器。这层还会根据日志类型,比如是某个定制的大客户的日志、内部人员使用的日志等,将日志进行一致性哈希,保存到不同的 Kafka topic 。

日志会在 Kafka 集群里面进行暂存。在 Kafka 后面连接着成百上千个日志消费者(包括公司部门和客户),不同的消费者会消费不同的 Kafka topic,它会根据不同的需求,将日志转换成用户所要的格式。

潜在的两个问题

在日志服务过程中,可能会遇到些许问题,这里仅列举了两个问题,当然不止这两点,也存在一些其他值得关注的问题。

问题一:上传问题——由于 CDN 的特点,CDN 的边缘机房部署在全国各地和海外,通过公网上传日志如果遇到部分网络不理想的情况,就会上传失败、丢失。

问题二:日志消费赶不上生产的问题——上传成功,都保存在 Kafka ,但是日志消费者消费能力有限的时候,会导致 Kafka 队列发生堆积。

机房掉电也是很严重的问题。不过又拍云的 Kafka 集群所在的机器装备了双电源,保证它至少在 99.9999% 的情况下,不会出现掉电影响服务。

下面我针对这两个问题,聊一聊又拍云的解决方法。

日志上报方案:解决日志上传问题

我这里说的“日志上报”,指的是又拍云针对 Nginx 日志格式的上报方案。

第一种是通过脚本周期性地向 Nginx 发送信号进行日志切割,然后把日志归档上传。这种方式有个弊端,Nginx 是一个基于事件循环来展开工作的,它最大的敌人就是阻塞,Nginx access.log 目前写磁盘采用的是同步的方式,而且经过了文件系统,极有可能哪个文件系统或者磁盘抽风,整个进程就卡住,导致这个进程内的所有请求一段时间内会处在“饥饿”的状态,影响到它的工作。这种方案看起来显然不是特别完美。

第二种是利用 Nginx 在 1.7.1 版本所支持的直接将产生的 access.log 发到外部的 syslog 组件的方案,这个方案存在一个缺点是如果发送失败日志就会直接丢失,所以也不是特别符合我们的需求。

考虑到又拍云的服务所产生的日志数据相对比较复杂,直接用 Nginx 的 access.log 是不能很好地描述这些日志数据,因此我们采用了以下的方案:

  • CDN 边缘机房引入单独的 log agent 服务,由它对接数据中心的日志代理层,即我们的 CDN 边缘服务不是直接发到日志代理层的;
  • 在 log agent 内置 disk queue;
  • CDN 边缘服务引入基于 Nginx 所写的日志发送方案: lua-resty-logger-socket,将日志发送到本机的 log agnet (127.0.0.1)。

lua-resty-logger-socket ( https://github.com/cloudflare/lua-resty-logger-socket )是 cloudflare 针对日志发送的开源方案。该库有一个核心的内存 buffer,它会把上传所提交来的日志数据全部暂存起来,buffer 的内容只会在达到一定大小(flush_limit)之后才将数据冲刷出去,如果发送失败,内容不会被丢弃;如果缓冲的数据大小超过一个硬性值(drop_limit),那么当前的日志会被丢弃。

这个库是基于 nginx_lua 的 Cosocket 技术,Cosocket 通过利用 Lua coroutine 的 yield / resume 特性,完美结合了 Nginx 的事件框架,因此是百分百非阻塞的,这避免了 access.log 写磁盘带来的阻塞问题,和又拍云的 CDN 服务的软件架构非常契合。

接下来日志就到了边缘的 log agent 组件,我们内部称之为“logger”,接收 CDN 边缘服务所发来的日志并进行转发。其实它做的事情很简单,周期性地把日志转发出去,如果网络质量相对比较理想,这些日志只会被短暂地缓冲在内存当中。而如果网络出现异常,内存里的日志会越来越多,当超过某个阈值的时候,日志会自动加入到 disk queue ,这是一个基于文件系统的先进先出队列,当需要转发日志的时,会优先处理在内存和磁盘中排队的日志数据。

如果网络一直很差,日志一直堆积,甚至本机磁盘都不够放,那这个问题就太严重了。这种情况下因为毕竟磁盘容量有限,所幸我们有完善的报警机制,基本上只要出现问题我们立刻就会发现,然后运维和研发会去介入并解决问题。

通过这套机制保证日志即使在网络情况不理想的时候也不会被丢弃。如此,就解决了上面的第一个问题:公网网络不理想的情况下,日志上传不上去,出现丢失的问题,CDN 边缘机房日志上报可靠性得到了保障。

自研 Morgans 系统:让“日志消费”跟上“日志生产”

又拍云的日志种类繁多,包括内部使用、客户使用或者通用的等,需求也不尽相同,所以需要一个通用的日志消费者(包括需要调用日志的公司部门和客户)框架,避免重复劳动,满足不同的需求,基于此,又拍云自研了 Morgans 项目 。

又拍云没有采用开源的日志解决方案,有几个具体的原因:

  • Logstash 使用了 JRuby 作为插件编写语言,而 JRuby 对资源的消耗比较重;
  • Logstash 本身存在不少缺陷,容易踩坑;
  • 某些业务场景十分复杂,例如需要适配客户的 FTP 服务器;或者某些客户的服务器需要先进行鉴权;又或者日志需要进行分类和打包;
  • Mozilla Heka 项目多年未更新,许多问题也得不到修复;
  • 自行设计能够更加贴近业务需求,更加轻量,即使出错也能够快速定位解决。

目前 Morgans 系统已经接管了又拍云所有日志定制和内部监控数据的处理,消耗的 CPU 、内存均比较少,稳定且基本无害。

容器化:解决日志生产和消费的思路

如果日志到 Kafka 这一层没有问题,但日志消费者不给力,这会直接导致了日志数据无法及时传递到下一层,破坏了整个系统近实时的传输转发能力。如何增强消费能力?消费者在设计上需要支持水平可扩容,才能从容应对日志量突增的情况,避免服务可用性降低。

如果新增一种消费者程序或者扩容时,需要提前申请物理机、人工推送服务上线、部署对应的监控报警程序等,全部弄完可能一天的时间已经过去,但是问题还是没有解决,整个操作周期很长,如果是紧急的情况,可能会带来不少的损失。

相比之下,使用容器云平台的优势就非常明显:

  • 资源池化,需要多少 CPU 、内存就配置多少;
  • 拥有故障转移能力,弹性伸缩;
  • 运维成本降低,只需要在网页上配置一些东西,整个服务就布上去了;
  • 自带监控报警,目前对接到了 Slack,如果服务挂了,会推送消息告知什么原因使容器的程序挂掉了。
【技术干货】日志服务架构设计和实践

上图是在又拍云容器云平台上创建一个服务,首先创建一个组和相应的名字,最重要的是填入容器镜像的下载地址,包括启动命令、需要多少 CPU、多少内存、磁盘等。配置完成后,服务就起来了,可以说运维成本相对比较低。

【技术干货】日志服务架构设计和实践

上图是日志消费者服务的部分运行监控图,第一个是 CPU 监控图,平均每个容器占用的 CPU 变化;第二个是内存的监控图,可以看到内存使用非常平稳,如此可以了解大概是怎么样利用我们的服务资源。

模块设计:沿袭自 Nginx 的设计哲学

Nginx 的设计哲学是一些皆模块。Morgans 项目也遵循了这个设计哲学,内部也有四个模块:

  • Input module:从 Kafka 或其他日志源消费原始格式的日志
  • Filter module:根据需求转换成目标类型的日志
  • Output module:根据需求转发或者暂存到目标服务
  • Core module:消费者框架代码

Morgans 的模块设计借鉴了 Nginx ,Nginx 的模块设计已经相当漂亮,可以自己注册一些配置指令,如果配置想提供给用户,就注册这样的配置项。Morgans 也如法炮制,每个模块拥有自己的配置结构,可以注册配置指令,注册各类功能的钩子函数。这些钩子函数在不同的阶段发挥各自的作用,这种用法可能会颠覆了大家对 golang 语言使用的看法。

【技术干货】日志服务架构设计和实践

如上图,是 Morgans 前端的一个模块结构体,名字、配置项、类型,包括 PostParse 处理到某条配置文件指令时,某个模块的某个配置指令钩子会被调用,从而正确解析到该配置;配置文件解析完毕后,模块的 PostParse 钩子会被调用;准备开始工作时,模块的 InitProcess 钩子会被调用等。

如果编译过 Nginx,一定知道 Nginx 的目录下有一个 auto 子目录,其目录下的 configure 脚本是用来定制其构建配置的。通过它可以选择编译哪些模块,打开某些功能等。与 Nginx 类似,Morgans 每个模块都会有一个 config ,可以让他设置几个变量,包括名字、模块类型、钩子等,通过只编译需要的模块,还可以减小编译得到的二进制文件大小。

灵活的配置文件设计

Morgans 拥有灵活的配置文件设计,首先指令式的配置方式,简洁而不失描述能力。

其次,Morgans 支持从外部的 key-value 存储中加载配置。当我们在容器云平台配置消费者时,需要给他们提供镜像,包含了消费者二进制和全部配置,如果某个时刻我们得去更新配置,那么就需要重新构建镜像并上传,镜像在 CI /CD 中构建相对比较慢,而如果它能够支持外部读取内存,那就会快很多(无需重新构建镜像,只需要重启服务即可),目前我们使用满配置的 hashicorp 公司开源的 consul,把它作为一个 key-value 的存储,我们某个时刻修改了配置,在容器云平台找到对应的服务,重启一下就能生效。

第三是结合消费者框架内置的变量系统,实现了变量插值功能。

【技术干货】日志服务架构设计和实践

上图是变量插值的示例,进行 input::kafka 的实例 mykafka ,定义一些需要的设计,比如 topic mytopic 数据如何分割、定义换行符来区分、配置多少个 broker 、消费者组是什么,最后还有 offset 的管理等。

下面定义了一个 filter ,比如有一个 common 的过滤模块,随便给个名字,后面是 一个 hdfs output 模块,包括文件的 replication 属性、hdfs namenode 的地址、user等。在 filepath 里面, 【技术干货】日志服务架构设计和实践 mylog_timestamp 称之为变量。整个 filepath 的配置利用到了变量插值的技术,即取出配置里的源字符串,转换为中间形态,使用的时候去解析,得到目标字符串。

Morgans 内置了一套简易的运行时变量系统,和 Nginx 的类似,这套变量系统关联到每个日志对象,每个模块可以自行注册变量,以及变量被使用时需要调用的钩子,钩子则可以关联到一个日志对象的上下文。使用分成两步,第一步会处理源字符串当中每个变量和常量并解析得 到 ComplexValue 对象,第二步是发生在需要使用时,调用这项变量和常量的 handler 从而拼接得到经过解释后的完整字符串。这样做的好处是什么?比如有很多用户他们都存到了 HDFS https://github.com/tokers/corgi)


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

How to Think About Algorithms

How to Think About Algorithms

Jeff Edmonds / Cambridge University Press / 2008-05-19 / USD 38.99

HOW TO THINK ABOUT ALGORITHMS There are many algorithm texts that provide lots of well-polished code and proofs of correctness. Instead, this one presents insights, notations, and analogies t......一起来看看 《How to Think About Algorithms》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具