前言
大数据一直是技术社区的热门话题,是从事大型服务架构的攻城狮必修之课。
岳鹰全景监控平台作为大数据应用系统,每时每刻都需要处理大量的日志流量,今天我们将通过本文,为大家介绍岳鹰是如何打造大数据日志网关(简称网关),以满足以下需求:
QPS | 数十万 |
---|---|
日PV | 数百亿 |
流量带宽 | Gbps级别 |
日流量 | 数十TB |
RTT | <=40ms |
数据安全性 | 高 |
服务可用性 | 99.99% |
背景
一个监控系统大致包括四个阶段:日志采集上报、日志存储、统计与分析、数据展示,具体如下所示
而作为整个链路的数据入口,可以把网关想象为通往皇城前的守门将,所有的数据流入都需要经过其“把关”,才能到达下游被处理
业务特性
概括来说,网关其核心设计要素主要有安全、高可用、大流量、高并发以及成本5大特性,如下图:
安全性
作为一个对外暴露的服务,安全性必定是凌驾于一切之上的。除常见的物理层、网络层、系统层的安全防御以外,在应用层,我们通过以下手段保证数据安全性:
- Https——作用不多说,请自行Google
- Params Verify——常规的入参信息校验
- Time Verify——请求超时校验
- Sign Verify——签名校验,通过请求信息、应用标识、应用秘钥生成
- Business Verify——业务级校验,如App是否存在有效、数据是否被限流等
- Encrypt/Decrypt——数据加密上报,网关解密处理
- No Store——本地无存储,防止服务器被黑客入侵导致数据泄漏
除此以外,还有防刷判断、请求重复判断、限流熔断等一些列保障措施,这个后面会有专门文章解读,敬请期待...^v^!
高可用
可用性决定了整个平台的数据可用性(若垮掉整个下游都不会再有数据),因此需要有以下策略保证其服务可用性:
整个架构非常经典,各核心职责:
- 日志数据由应用端利用SDK通过互联网上报至合适的服务节点;
- 由统一服务层,完成https数据解密、请求路由、负载均衡操作;
- 具体的业务操作由日志网关应用负载进行业务层处理;
- 过程当中需要用到的相关业务数据,通过Redis集群加载,并利用广播机制实现实时数据刷新;
- 当日志完成初步处理后,会发往Kafka集群,并供下游服务使用;
大流量&高并发
如上文说述,网关需要
- 处理 百亿级以上/日 日志上报请求(按16小时分布计算,QPS达十万级别)。
- 接收 约数十TB/日流量(按16小时分布计算,需要带宽Gbps级别)。
- 毫秒级请求响应能力(否则有可能影响调用端的整体性能,或丢失数据)。
偶遇极端情况,还会呈几何级别上涨(想了解如何处理这种极端情况,请期待后面推文)。可见要解决这一问题,比“安全性”、“可用性”要困难的多。在说解决方案之前,我们不妨先大概了解下整个上报的处理流程:
核心(长耗时)的处理逻辑集中在“请求校验”、“业务处理”两个环节。当中又可以划分为“CPU密集型”和“I/O密集型”(小乌龟图标位置)操作。
CPU密集型
网关并非复杂运算形应用,针对纯CPU操作的优化其实非常有限。值得注意的是,现代主流的编程语言(如Java、Node等),其在逻辑运算能力上的差异一般不会很大(当然不同技术有其特殊的优化手段),而在实际情况下,提升硬件性能、利用负载均衡这两个手段效果会最为明显。
I/O密集型
I/O操作一般都会比纯CPU/内存操作要慢得多,当中又要细分为本地I/O和网络I/O两种:
解决这方面问题,我们的手段是:
- 数据压缩上报——提高网络传输速度,减少带宽耗损。
- 合并上报——减少并发请求数,提升压缩质量。
- 分阶段请求处理——http请求处理实际上是分多个阶段的(如Nginx就分了11个阶段),可以把大量用于校验的信息(该类信息通常比较小),通过http头部传输,并在header处理阶段完成校验操作;若检验失败就可以直接不处理报文体内容,这样可以减少非必要的流量处理,节省资源&提升效率。
- 跨系统调用——利用中间件代替直接的跨系统访问,拥有更高性能同时,降低性能不稳定风险。
- 高性能中间件选型——用Redis替代传统DB作为数据源、用Kakfa作为消息中转替代直接的下游系统访问。
- 多级缓存——把不常变的数据,利用本地->集群缓存->物理存储方式进行缓存,减少I/O操作及运算耗时。
- 数据缓冲 & 中转——在大数据分析处理的场景,我们需要对数据进行不同类型的加工处理(如统计、聚合、筛选、过滤等),若这些操作都在一次请求中完整处理,耗时会非常长。因此我们使用异步缓冲机制,利用消息中间件对数据进行缓冲,并中转至下游运算,这样可以大大降低RT,提升TPS&QPS。
- 调整日志输出级别——上线后的应用,调整较低的日志输出级别(如error),可以减少本地磁盘的写入操作。
- 线性落盘——针对需要写盘的操作,可以统一写到全局缓冲区,然后用独立线程/进程进行落盘操作,减少不规律I/O操作。
当然以上的方案是需要根据实际情况权衡使用,如使用缓存会导致变化响应慢、使用线性落盘数据会有丢失风险等。
成本
作为一个如此大流量、高并发的产品,我们需要承受各类硬件、网络、维护等的高成本投入(当然还有其它),因此在技术方案上,我们必须要考虑这个因素:
- 硬件成本——如何提升同等级别设备下,单实例的运作效率。
- 网络成本——如何在不影响(小影响)性能效果下,降低网络资源耗损。
- 维护成本——如何通过更多DevOps工具(部署、测试、监控),减少人工成本投入。
- 人力成本——包括学习成本、实施成本、问题跟进成本。
- .....
技术选型
在选型的道路上,我们纠结了很久(也踩了很多坑)。最初我们曾用SpringBoot(Web层用原生Servlet,MVC性能很差!)实现了一个日志上报的demo,在16核8G内存下(并做一定配置调优),跑出单机1W+QPS的成绩。但干了Java那么久,又好像没怎么听过用Java Web来做高并发大流量网关的(Go、NodeJs:我们这方面精通!!!)。
于是我们开展了一波又一波的研讨,包括同类竞品分析、各类技术调研、各种性能评测等等(有机会再分享下我们的选型经过)。最终我们综合各方面因素,最终选型——OpenResty(Go、NodeJs:What?!)
OpenResty简介
OpenResty是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。
总结特点:
- 基于 Nginx 与 Lua 的高性能 Web 平台(利用Nginx扩展机制,通过模块方式集成Nginx运行进程)
- 部署简单方便
- 专注超高并发、扩展性极高的动态 Web 应用、服务和动态网关
- 非堵塞I/O、协程同步模型(比较适合密集小文件I/O请求场景)
- 支持细粒度请求事件控制(结合上文提及的分阶段请求处理)
- 学习成本低,轻量级Lua脚本语言(与nodejs相像),支持JIT
- 有成功案例,也有同类应用场景案例
- 同时根据评测,在相同硬件环境、业务逻辑的前提下,OpenResty都会有比较明显的性能优势。
但是,它也有一些不足的地方:
- 冷门技术,学习成本高
- 语法有点不习惯,特别是数组索引是从1开始!!!
- "集成大量精良库",支持并不完善
- 配套的开发、测试工具不丰富
- 运行性能与编码实现方式非常密切,一不小心就可以掉30~40%性能
- ......太多了,有机会再分享
能力扩展
正如上面说到,OpenResty原生的支持不算十分强大,为了更好的落地这个方案,我们还是做了一定扩展,包括:
- lmf-mvc——纯lua编写的mvc框架,提供多层交互模型,解决原生配置复杂且实现混乱问题
- lmf-redis——纯lua编写的Redis组件库,支持更多redis部署模型以及更多能力特性
- lmf-commons——其它常用组件,提供如多级缓存组件、并发锁、日志、各类方法库等能力
- ......
技术架构
说那么多,还是来个图比较实际:
新的方案为我们带来了更高的性能提升,在相同硬件情况下,新的方案QPS提升了3倍以上。同时硬件层面的提升对性能的影响也能起到更明显的效果。
小结
由于篇幅关系,大数据日志网关的介绍就到此为止,若大家想深入了解更多内容,欢迎各位关注我们,深入讨论~(小编又要回去码代码了)。