从0开始构建核心业务微服务治理平台的实践
导读
近年来,FreeWheel核心业务开发团队致力于将传统单体Rails应用,向分布式微服务架构迁移,以适应越来越复杂的业务场景和系统性能的提升。随着微服务规模的不断增长,一些新的问题也随之产生。其中如何对这些业务服务进行有效的治理和维护,对业务状态进行监控,甚至于线上调试变得尤为重要。业务服务治理平台(business service management platform),是我们为应对这一挑战做出的选择。本文将详细解析FreeWheel核心业务开发团队构建的服务治理平台。
为什么需要服务治理平台
随着Rails单体应用向分布式微服务架构迁移的深入,面向不同业务和层次的微服务如雨后春笋般诞生,微服务集群的规模迅速增长。架构迁移让我们可以把业务重新梳理、聚合和解藕,不同的微服务可以聚焦自身业务,自成体系进行维护,减少了对其他业务的影响,增加了系统整体的可扩展性。但同时,这也导致有越来越多的微服务需要治理,原本只需要对一个单体应用进行监控管理,如今需要对几十个甚至上百个微服务进行管理。另一方面,分布式架构本身也会引入一些在单体应用时期所不存在的问题,例如分布式事务、消息等,对于这些方面我们也缺少相关的治理平台。因此,在我们的分布式微服务实践过程中,经常需要面对以下这些问题:
·微服务在出错或响应慢时,如何能进行简单快速的调试,以便了解是微服务本身的问题,还是所依赖的服务有问题?
·相比于单体应用,分布式系统更容易引入数据不一致,如何对这样的数据进行监控?
·在基于异步消息的业务中,某个主题的业务没能正常完成,是生产者没有把消息发出来?还是消费者没有接收到消息?
·为什么数据库已经更新的数据迟迟没有生效?缓存数据何时过期?
·我们有哪些后台任务正在执行?执行的排期如何?执行失败的原因是什么?
·等等……
微服务的部署层面我们可以通过业界云原生的解决方案来实现,而这些业务层面的问题却很难找到一个公共的解决方案或者治理入口,因为这往往是跟具体的业务场景深度绑定的。不同的微服务业务场景和功能不同,但基本都遵从类似的开发实践,使用相同的基础组件,这使得我们对微服务进行治理成为可能。
需要注意的是,这里我们关注的重点是业务,而不是基础组件,例如我们不关注异步消息机制或组件(Kafka)本身,我们信任基础组件是正常工作的,而关注基于它所实现的某些业务上的问题。在这些问题解决之前,工程师往往需要耗费巨大的精力在线上环境进行调试、监控或处理。
基于此,我们决定从0开始构建一套适用于FreeWheel自己业务场景的服务治理平台,来对分布式微服务进行业务治理,解决工程师的痛点。
业务微服务治理平台实践
总体来看,我们构建的服务治理平台有以下几个方面需要考虑:
1.业务服务治理平台在某些功能上,需要和FreeWheel特有的业务深度绑定。
2.避免与FreeWheel已有的PQM(FreeWheel监控平台), FOC(FreeWheel运维中心)等模块功能重合。
3.平台应轻量级,能快速迭代开发。当有新需求出现时,可以更快更好地对平台进行横向扩展。
根据上述提到的应用场景,我们需要构建的是一套基于Web UI的业务服务治理平台。它需要和业务微服务通信,和服务集群中的公共资源进行整合,并包含许多业务监控和治理等功能,因此它应该位于微服务集群中所有微服务之上,如下图所示。这套平台被命名为Falcon,可以直接在生产环境中使用。
技术选型与架构
针对服务平台Falcon的构建,我们从以下几个方面进行了技术对比和选型:
根据以上对比,基于对治理平台快速开发、稳定运行的要求,我们最终选用React+Nodejs+Mysql+AWS RDS的组合来进行开发构建。
按照FreeWheel今天的业务场景需求,我们的治理平台将包括四个主要的部分:Falcon前端,Falcon后端,数据库,Redis。
为了与现有的服务集群进行整合,我们需要将治理平台的各模块部署在AWS集群中:
其中:
·Falcon前端主要提供所有的Web前端资源和逻辑,它是独立于后端进行开发和部署的,实现了前后端的分离解耦。
·Falcon后端是整个平台的后端服务器,负责平台的所有业务逻辑。同时它需要和集群中的业务微服务和公共组件进行通信交互。
·数据库用于存储平台自身的数据,例如登录用户的信息、采集到的业务数据等。
·Redis模块是为了实现定时任务等功能点所引入的模块。为了尽量减少对线上微服务的影响,我们没有使用集群中业务微服务所使用的Redis,而是重新部署了一个单独的Redis。
我们将Falcon前端/Falcon后端/Redis打包,以Kubernetes Pod的形式运行部署,和FreeWheel的业务微服务部署在同一个AWS EKS集群中,而数据库使用了AWS RDS服务来支持。我们对Falcon前端/Falcon后端/数据库暴露了VIP, FreeWheel内网进来的请求,会先经过AWS ALB,转发到服务网格Ingress Gateway,最后打到Falcon对应的Pod或数据库。
Falcon与EKS集群的交互主要通过Falcon后端完成:订阅监听Kafka传递的消息;搜索读取集群Redis中的数据;对业务微服务进行接口调用等。其中,Kafka是FreeWheel使用的分布式消息发布订阅系统,用来传递业务微服务之间的异步消息;Redis用于缓存一些不易变的业务数据,或者用于存储实现后台任务;业务微服务处理业务请求,会跟AWS S3等设施配合实现业务,使用Aurora存储业务数据,与Free-Wheel后端服务进行交互等。
平台运行工作流
当Falcon被部署运行使用时,会经历以下过程:
1.部署之后,Falcon后端开启消费者监听Kafka消息
2. Falcon后端加载数据监控配置进Redis,开启任务调度
3.用户访问VIP地址,请求被路由到Falcon前端Pod, Falcon前端返回JS资源
4.浏览器加载并渲染前端资源,进入登录页面
5.用户输入LDAP用户名/密码,请求路由到Falcon后端,Falcon后端验证登录,存储登录信息进session和数据库
6.用户在平台界面操作,请求路由到Falcon后端,将操作数据存储,或实时调用业务微服务,完成对应操作
平台提供的功能模块
今天Falcon针对于业务团队的痛点实现了许多功能模块,还有一些功能模块正在探索和开发中,下图是Falcon的导航首页。
接下来本文会围绕Falcon的这些功能模块进行介绍:登录验证,数据监控模块,后台任务模块,异步消息模块,业务缓存模块,线上调试模块,用户管理模块和使用记录模块。
准备工作 - 登录验证
出于系统平台安全性的考虑,我们限定了只有在FreeWheel内网才可以访问Falcon平台。平台的使用用户限定在FreeWheel的工程师团队,而FreeWheel内部员工使用LDAP来做账号的统一登录认证,因此Falcon后端也集成了LDAP对登录用户认证。在用户首次登录时,Falcon会将该用户同步存储在数据库中,以便之后为其配置在Falcon平台的用户权限。
数据监控
数据监控模块旨在监控异常的业务数据。在从Rails单体应用迁移到分布式微服务后,很多数据的增删改不再由原来一个数据库事务来完成,而是变成了多个微服务多个数据库事务来进行数据更新,因而很难保证不同微服务间的数据强一致。一个简单快速的方案就是对业务不一致的数据进行监控,Falcon提供了这样一个入口进行脏数据的监控和报警,用户可以通过提供一段SQL语句,或者是微服务实现的一个接口,来达到对特定数据的监控目的。
如上图所示,Falcon后端在启动完成后,从数据库加载数据监控设置,初始化基于Redis的任务队列。任务队列中的任务根据设置好的排期,定时调用Handler执行SQL或调用接口,将执行结果写会到数据库。同时将执行结果与用户设置的参数进行比较,一旦发现满足脏数据条件,即进行报警通知订阅者。今天Falcon提供了Email和Slack两种方式进行报警通知。用户可以实时更改监控设置,Falcon后端会将用户的实时更改持久化,并更新任务队列即时生效。
后台任务
后台任务一般分为定时任务和按需任务。相信大部分的系统平台都有与自身业务相关的后台任务,FreeWheel也不例外。
在Rails单体应用的年代,FreeWheel使用Resque对后台任务进行管理,Resque自身也提供了一套基于Sinatra的Web管理界面。迁移到Golang微服务之后,FreeWheel使用封装的bricks/job作为后台任务管理工具,创建、执行、重试、销毁后台任务。然而相比于Resque,它对于工程师的痛点在于无法进行可视化的管理。
针对这一痛点,我们在Falcon中构建了后台任务的可视化模块,提供5个方面的内容:Worker Pool, Queue, Scheduled Job, Retry Job, Dead Job.用户可以查看到正在执行的任务有哪些,队列中已有哪些任务,将要执行的定时任务分别安排在了什么时间,重新过的任务是哪些,哪些任务执行失败了等等。例如下图中展示了Inventory Service中每10秒执行一次的default check alive任务的排期情况。
特别的,我们可能更关注于哪些任务执行失败了,以及失败原因,因此我们把失败任务的诸如参数、错误内容等详细信息展示出来,并提供了重试功能,以便在工程师在排查完错误原因后,可以手动触发重新执行任务。如下图展示了Order Service最近执行失败的任务、任务参数、失败原因等等。
异步消息
随着微服务集群规模越来越庞大,业务越来越复杂,异步消息机制也被越来越广泛地应用,微服务在很多业务场景中都需要发送/接收异步消息。从工程师的角度,我们很希望能实时得知消息是否被成功发送到Kafka,发送的消息内容是否是我们所期望的。以往我们只能通过查看日志的方式来获知消息的发送情况,这对工程师是非常不友好的。在这个模块,我们通过新加消费者监听消息的方式,并将监听消息展示,实现了Kafka业务消息的可视化。
Falcon后端启动完成后,从数据库加载异步消息监听配置,最主要的是消息的proto格式文件,通过proto handler将消息格式解析,并启动初始化consumer监听该topic消息,将监听到的消息存储回数据库,并构建UI对这些数据进行展示,达到了业务消息可视化的目的。
由于随着新业务的出现,新的消息也会不断增加,为了应对和支持越来越多的新消息,我们也做了动态添加新消息类型并监听展示的功能。当我们的微服务中增加了新消息,只需要将新消息的topic/消息的proto定义文件/消息的名称配置好,Falcon会将配置实时存入数据库,并动态加载这个消息并监听展示。由于消息量巨大,考虑到存储成本,以及我们对历史已久的消息并不感兴趣,在数据库层面我们设置了Event Scheduler定期对历史消息进行清理操作。
业务缓存
为了提升微服务的处理能力和响应性能,减小业务层对数据库的压力,我们会在领域微服务中加入缓存,将常用不易变的数据放到缓存中。每次有新的请求过来,先查询缓存,如果有数据并不过期,则直接读取返回。类似于后台任务模块和异步消息模块的问题,缓存中存了什么,有效期多久,何时进行的更新,在微服务运行时我们是无从得知的。
一个常见的场景是,数据库中的数据更新了,却不能很清楚地知道数据何时能生效,在定位问题时很容易导致判断错误。在这个模块中,我们将缓存数据进行了可视化展示,提供搜索功能以针对特定的key进行查询,用户可以很清楚地看到有哪些数据被缓存,数据量多大,到期时间等等。如下图展示了Metadata Service中当前缓存的业务数据情况。
线上调试
领域微服务的业务中,往往需要依赖于第三方的服务,而在生产环境中这些第三方服务发生问题时,我们很难快速地从微服务的角度进行问题定位。比如下层服务响应慢,微服务对外的表现也是响应慢,但很难确定是微服务本身操作数据库慢,还是调用下游服务响应慢。不同的微服务可以根据自己的业务情况,实现自己的调试接口,提供调试信息。线上调试模块提供了调试入口,将调试接口集成到平台调试模块,用户就可以在平台手动触发,查看整个链路的执行情况。这在发生线上问题时,能帮助工程师快速定位出错原因,节约处理时间。
以Advertising模块为例,今天它主要依赖于Feedback/Counter/Conflict Detection/Presto/S3等服务,我们针对于这些依赖都接入了特定的调试接口。平台本身提供了快速接入其他接口的代码模板,在有新的需求出现时能快速扩展。
用户管理
Falcon平台的功能和架构定位,决定了它的重要性和影响程度远高于微服务。尽管平台致力于实现对于业务有保护性质的功能,但仍有必要对登录使用该平台的用户进行管理,以避免发生误操作造成严重影响。我们采用了通用的用户-角色-权限模式来进行用户的管理,每个功能模块都定义了读写权限,细化到微服务,在此之上按团队划分配置了工程师角色,只需要给不同用户以相应的角色,即对该用户在平台的操作权限进行了控制。如下图是给一个Advertising团队工程师的权限。
使用记录
作为平台系统完整性的一部分,也为了更好地追踪平台上的设置更改,我们实现了使用记录模块,以记录在该平台上发生的所有更新操作。由于平台本身没有特别的复杂业务,同时更新不会特别频繁,因而在记使用记录时我们选择记录使用全量,而非变量,即当某个对象发生变化时,都将原始对象的快照进行全量备份。下图是某次更改设置的新值与旧值的对比,通过记录全量,我们能很清楚地看到某一时刻整个数据的状态,也能很容易地看到那些字段发生了变化。
结语
Falcon作为FreeWheel核心业务开发团队从0构建的一套微服务治理平台,提供了诸如数据监控、异步消息等功能模块,帮助工程师解决了很多在分布式微服务架构时期所面临的业务治理或监控痛点。目前这个平台只提供了一些对工程师而言最急切的功能,很多地方还有待进一步提升,未来我们会从以下几个方面进行持续进行工作:
1.对已有的功能进行持续优化完善,确保平台稳定可靠
2.探索对分布式事务的集成与支持,以对异常分布式事务进行控制
3.提供配置中心功能,集中管理业务微服务配置
4.集成报警,让工程师可以简便快捷进行预警配置
5.支持功能快速扩展,当有新的功能需求时可以快速集成
对于微服务治理我们还是新人,未来我们仍将在这条路上持续学习、深入探索。
作者介绍
尚鹏飞,FreeWheel高级研发工程师,任职于FreeWheel核心业务开发团队,擅于解决后端业务系统的复杂问题,有丰富的开发经验和敏捷团队管理经验,热衷于新技术的探索与分享,目前致力于Golang微服务和系统重构相关工作。