当前位置: 首页 > 后端技术 > Java

Apache神羽集成RocketMQ实时采集海量日志的实践

时间:2023-04-01 14:19:26 Java

本文作者:胡太石,快手Java开发工程师。关于Apache神鱼(ShenYu)网关最需要了解的就是流量治理,而流量治理与大禹治水有很多相似之处。因此,网关的流量治理项目被命名为神域。ShenYu是一个高性能、多协议、易扩展、响应式的API网关。其主要特点包括丰富的协议、插件、流量管理和高性能。神鱼支持HTTP、SpringCloud、gRPC、Dubbo、Sofa、Tars、Motan等协议。为保证可扩展性,神鱼采用插件式设计,支持热插拔,内置丰富的插件。插件化设计最大的优点就是扩展性强。神鱼有大量的流量管理功能,对应不同的插件。神羽支持鉴权、限流、熔断、安全、负载均衡、灰度、动态上行、可观察性等丰富灵活的流量管理。由于对网关的性能要求特别高,神羽采用响应式全链路异步系统,支持集群部署、蓝绿发布等。客户端通过网关发起请求,网关再将请求转换为服务提供者,将服务提供者的响应发送给客户端。从发起请求的角度看架构,支持多种语言,不局限于运行平台。HTTP请求首先经过一层代理层,可以是Nginx、ShenYuNginx、ShenYuproxy或者K8s,通过负载均衡将请求路由到ShenYu集群中的节点。神鱼网关收到请求后,首先对请求进行过滤。为了保证性能,网关将各种元数据存储在本地内存中,并配合高效算法实现高性能。数据请求处理离不开元数据,而元数据的获取主要依赖于神羽网关与神羽后台的同步机制。神羽管理后台发生数据变更后,如插件变更、选择器变更、规则变更、数据变更等,都会以一定的方式同步到神羽网关。用户可以根据项目特点选择pull或push同步方式。首先需要对流量进行过滤,可以根据请求的URL查询参数、请求头、请求参数、host或者请求体进行匹配。匹配条件可以是like、match、regularexpression、inclusionorexclusion等,然后通过SPI加载相应的实现。如果流量匹配,则将流量转发到相应的插件。每个插件组成一个插件链,每个插件链执行其插件功能匹配流量。最终请求会通过导出插件转发给服务提供者,然后服务提供者的响应转发给客户端。是监控网关运行状态的一个非常重要的模块。可观测指标登录的请求量可能非常大,导致日志量很大。这种情况一般需要集成消息队列。神羽的流量筛选流程如上图所示。每个请求都有一定的元数据,可以根据这些元数据进行匹配,过滤出需要的请求。神羽的流量过滤有两个非常重要的组件,选择器和规则。请求到达后,首先判断插件是否启用。如果不启用,则不处理;如果启用,插件对应的选择器将判断请求是否匹配。如果请求匹配,则将其交给规则进行另一次匹配;不匹配则交给下一个插件处理,匹配则执行插件。选择器相当于一级匹配,是一种粗粒度匹配,而规则相当于二级匹配,是一种细粒度匹配。这种设计可以保证更高的灵活性。插件组成一个插件链,上一个插件执行完毕后,再决定是否交给下一个插件处理。流量筛选还必须要求流量处理。流量处理会将服务提供者连接到神羽网关,并提供一系列神羽客户端来访问服务提供者。服务商依赖神宇的接入客户端。当服务提供者启动时,神鱼客户端会获取元数据信息,并将元数据信息发送给Disruptor。注册中心的客户端会获取到Disruptor中的数据。发送到注册中心。注册中心支持HTTP、Zookeeper、Nacos等多种方式。在注册中心服务器端,神鱼管理员会监控注册中心的数据变化,可以配置选择哪个注册中心,选择哪种同步方式。神羽管理员监听到元数据的变化后,会同步到神羽网关,比如通过保存MySQL持久化或者通过Zookeeper同步到神羽网关等,再更新到本地缓存。神宇的流量管理是动态的,使用起来非常灵活方便。神羽网关与后台同步时,如果用户操作元数据或通过API操作元数据,神羽admin检测到变化后,会通过SPI方式加载用户配置的同步方式,支持PullHTTP等方法也支持WebSocket等推送方法。神鱼网关监听到元数据变化后会立即更新缓存,对下次请求生效。神鱼支持插件热插拔,比如可以直接排除一些无用的插件,后台可以控制是否启用和配置依赖插件的各种元数据。另外,官方内置的插件无法覆盖所有场景,用户也可以自定义插件。ShenYu提供了一个自定义的类加载器。同时,社区也在通过管理后台开发和上传自己的插件,更方便用户操作。在注册中心方面,神鱼支持几乎所有的主流注册中心。上图是神羽贡献者人数的发展情况。可以看到,从2021年开始,贡献者数量呈现稳定持续增长的趋势,而2021年是神鱼向Apache捐赠的时间节点。这也说明,自从神羽加入Apache孵化器后,活跃度越来越高,贡献者和用户也越来越多。神羽社区的运营模式是社区大于代码,生态比较丰富,支持几乎所有主流的RPC框架,发展非常迅速。ShenYuObservabilityLog上图是ShenYu的可观察性日志架构。用户请求通过ApacheShenYu,Logging-RocketMQ插件实现日志。Logging-RocketMQ插件会将AccessLog日志放入缓冲队列,后台会设置一个日志消费者异步消费日志,然后将日志发送到RocketMQ集群。为了收集日志,需要启动另一个RocketMQConsumer,批量持久化日志,可以写入Elasticsearch、Clickhouse或其他DB。在可视化方面,可以选择Kibana、Grafana、Loki或者对接公司内部的日志系统。可以对日志进行日志聚合分析,针对日志情况进行告警,如请求量告警、请求耗时告警、请求异常告警等。日志中非常重要的参数就是输入输出参数,可以很方便的帮助排查问题。神鱼底层是基于reactor的异步非阻塞模式,是响应式网关和发布订阅模式。请求体和响应体面临只能获取一次的问题。如果当前日志取了一次Body,那么下一个订阅者就取不到Body了。AccessLog的收集需要完全没有副作用,属于辅助功能。入参集合采用装饰器设计模式,委托请求,继承ServerHttpRequestDecorator。发出请求需要以无副作用的方式覆盖getBody方法。do开头的方法是没有副作用的方法,采集鉴权就是从这个无用的方法中插入日志采集的代码。同时dataBuffer要采用readonlyBuffer的方式,避免没有副作用。这也是一种流式读取的方式,所以只有在doFinally方法中才能判断请求的Body已经被读取。输出参数的集合也采用装饰器设计模式,将响应委托,继承ServerHttpResponseDecorator,重写writeWith方法。同样,在writeWith方法中,先将Body参数从to转换,然后在doOnNext中收集响应Body,最后在doFinally中确认已经收集到响应Body,然后将日志发送到缓冲队列。当异常发生时,神鱼提供了一个全局的异常处理器,全局异常处理器中也加入了日志采集。排查过程如下:①收到异常的Metrics告警,但此时往往无法知道是哪个节点出错了。②关联相应的错误Trace,Trace最大的作用就是定位故障节点。③检查错误链接,定位源头。④从源头定位异常日志。上面的流程说明logs和Trace需要关联起来。请求生成的所有日志都需要连接起来,通常是通过TraceID。访问日志记录请求耗时,但不能准确记录哪些节点耗时长;也会记录请求失败,但不能准确记录是哪些节点出现故障;此外,还有各种异常错误,更多的可观察性数据可以加快故障排除。障碍。神羽日志插件与链接追踪关联方案如下:如果神羽日志插件配合其他链接追踪,在链接追踪插件中,以SkyWalking为例,链接追踪必然会访问ServerWebExchange,插件可以在ServerWebExchange中找到TraceID保存在ShenYu的context中,ShenYu的日志插件可以读取TraceID实现关联。如果只使用SkyWalking日志工具集,它有自己的关联,在日志配置文件中配置TraceID变量,然后通过字节码增强技术拦截convert方法,设置TraceID到输出日志。从右图可以看出,每个人都有一个TraceID字段,点击TraceID字段可以关联本次请求经过的所有链接。日志异步采集方案有两个要求:性能:要求网关追求极致的性能,所以日志采集和所有辅助功能不能影响网关的性能。资源方面:网关处理高并发的海量请求,日志采集要求尽可能低的资源消耗,保证对网关无副作用。一个请求会产生一个AccessLog,Admin会先判断是否满足配置条件。条件可以通过某些字段自行配置,从管理员配置并发送到Logging-Rock插件。此外,还可以配置采样。如果日志不符合抽样要求,将被丢弃。经过一系列的判断,还需要判断缓存队列是否有足够的容量。如果队列满了或者下游异常,日志也会被丢弃。如果直接将日志发送到RocketMQ集群,会产生IO调用。IO调用是非常耗时的,如果将日志放入内存缓存队列,耗时可以忽略不计,所以这里需要引入缓存队列。后台的LogConsumer会不断的从缓存队列中取日志,取到的日志可以进行压缩,压缩是可配置的,然后通过OneWay发送。有很多方法可以实现抽样。这里采用产生随机数取随机数余数的方法来判断是否需要对请求日志进行采样。但是,在神羽网关中并没有这样做,因为生成随机数是一个耗时的过程。操作,而网关具有非常高的性能要求。神羽日志采样采用位图实现,设置位图为100位,设置采样百分比,可以设置一定比例的位为true,其他为false,然后随机打乱。自增变量可以保存在内存中。每进行一次自增,就取这一层变量的余数,然后判断对应的位是否开启。如果启用,则执行采样,避免生成随机数的耗时方式。日志采集中的字段包括客户端IP、时间、方法、请求头、响应头、查询参数、请求体、请求URL、响应体、响应内容长度、RPC类型、状态、上游IP等。通过这些字段,它可以得到哪些请求耗时长,某类请求的数量,请求的异常情况。当出现异常时,可以通过上游IP定位到异常发生的上游。很多时候,整个集群中的任何一个节点都有问题,但也有可能是集群中部分节点的问题。这时候,上游IP的故障排除功能优势就可以发挥很大的作用。日志采集遇到的一大挑战是如何获取日志插件中gRPC服务提供者的IP。与Http和SprinCloud不同,gRPC负载均衡隐藏在底层,业务层无法访问IP,无法与响应式ServerWebExchange建立联系。另外,链路追踪中也需要获取上游IP。SkyWalking是如何实现的呢?SkyWalking通过字节码增强解决了业务层无法获取IP的问题,没有入侵。但获得IP并不容易。常规的方法是通过Channel.authority()获取peer,但是这种方法有很大的局限性:首先,不能适应负载均衡场景;二是不能适应广义的通话场景。网关是通过泛化调用的,泛化是在没有通道的情况下调用的。第三,不能适应域名解析场景。经过分析,可以从Netty客户端获取到gRPC底层客户端流量对应的IP,即权限。另外,由于延迟初始化,第一次调用该方法是一个空方法。由于gRPC请求有监听器,因此可以在onClose方法中处理它们。调用onClose表示请求已发送,这也意味着客户端必须完成初始化。但这种方法仍然不够准确,因此需要另一种方法。ClientCallImpl有一个getAttributes属性,调用Netty客户端流的属性。在此属性中包含RemoteAddr,即上游IP地址。ClientCallImpl是封装级别的,业务层无法访问,只能访问对象,通过反射获取IP。RocketMQ的集成主要基于以下两点考虑:第一,削峰填谷。业务高峰期可能会出现万亿级别的消息吞吐量。请求量越大,响应日志就越多。如果没有分布式消息队列,日志系统可能会崩溃或丢弃大量日志。引入RocketMQ可以实现削峰填谷。面对万亿级别的消息吞吐量,可以将大量的日志发送到RocketMQ暂存,然后消费者可以继续从RocketMQ消费。第二,脱钩。ShenYu是一个开源项目。每个公司和项目可能都有自己的日志系统。这些日志系统如何对接神宇呢?答案是解耦。神鱼集成RocketMQ后,可以将日志发送到消息队列,各个项目或者公司可以根据业务特点从RocketMQ消费日志,然后存储到自己的日志系统中。这种解耦方式更易于连接和维护,神羽社区提供了多种消息队列。RocketMQ具有以下优秀特性:金融级可靠性。丢弃日志可能会给统计带来很大的麻烦。例如,订单日志的丢失会导致交易金额不准确。纳秒延迟。神鱼网关对性能要求非常高,所以日志的消费要求尽可能高的性能,而RocketMQ有纳秒级的延迟。万亿级消息吞吐量。业务高峰期可能产生万亿条日志。如果RocketMQ的性能不强,是无法支撑如此庞大的日志系统的。海量主题支持。神鱼网关可以是多租户的,即不同的业务可以共享网关集群,不同的日志可以发送到不同的集群,可以实现更好的隔离。非常大的堆叠支持。当业务高峰期有万亿级别的消息吞吐量时,RocketMQ必然会积累大量消息,消费者无法在短时间内完成所有消费,因此消息队列需要能够支持超大规模积累。在使用RocketMQ采集日志时,由于网关对性能的要求很高,需要尽可能低的延迟来消费日志。选择OneWay发送方式,类似于UDP,这种方式不会等待Broker的返回确认,具有最大的吞吐量,但在极端情况下可能会造成数据丢失(可以接受)。配置管理方面,admin后台配置主题和参数,配置分发到客户端,可以控制采集哪些API,采样率,各种过滤条件,比如控制body的大小,可以如果数据包太大,则被丢弃。可以实时控制日志采集策略,还支持日志压缩,支持实时关闭或开启日志采集。在RocketMQ中需要集群部署,单节点部署可用性很低。集群部署可以更好的实现纳米级延迟,支持万亿级消息吞吐量,支持海量Topics,支持超大规模积累。以上是集群部署与单节点部署相比的优势。收集日志后,需要消费日志,主要是通过可视化手段。ShenYu是一个开源项目,可以对接各种开源项目,比如Kibana、Grafana、Loki等。Grafana可以在可观察性方面对Metrics、Logging和Trace提供一站式支持。可视化侧重于每个接口的请求量、耗时和异常情况,包括网络方面的字节吞吐量、发送/接收的字节数等。还可以配置告警,可以进行聚合操作,比如判断哪些接口的请求量环比突然增加,哪些接口的时间消耗突然增加,哪些接口的异常量突然增加等。加入ApacheRocketMQ社区,十年磨一剑。ApacheRocketMQ的成长离不开全球近500名开发者的积极参与和贡献。相信你会在下一个版本中成为ApacheRocketMQ的贡献者。在社区中,你不仅可以结识社区领袖,提升技术,还可以提升个人影响力,促进自我成长。社区5.0版本开发如火如荼,近30个SIG(兴趣小组)等你加入。欢迎立志打造世界一流分布式系统的同学加入社区。添加社区开发者微信:rocketmq666进群。参与贡献构建下一代消息、事件、流的综合处理平台。微信扫码加小火箭进群。另外,你也可以加入钉钉群,与RocketMQ爱好者广泛讨论:钉钉扫码加群