Node.js 个推首席架构师 Qcon 分享 | 微服务架构的那些事儿

HongJack · 2017年04月26日 · 最后由 flowerwrong 回复于 2017年04月29日 · 9346 次阅读

什么是微服务?

传统的单体服务架构是单独服务包,共享代码与数据,开发成本较高,可维护性、伸缩性较差,技术转型、跨语言配合相对困难。而微服务架构强调一个服务负责一项业务,服务可以单独部署,独立进行技术选型和开发,服务间松耦合,服务依赖的数据也独立维护管理。虽然微服务存在部署复杂、运维难度较大、分布式事务控制难、容错要求高等缺点,但总体而言,微服务的优点远大于其复杂性。

微服务架构需要注意哪些问题?

微服务架构,首先考虑客户端与服务端之间的通信问题。有两种解决办法,一是客户端与多个服务端直接进行通信,但存在对外暴露接口细节、众多接口协议无法统一、客户端的代码复杂、服务端升级相对困难等问题。二是客户端访问统一的 API 网关,由 API 网关调用众多服务接口,易实现统一通信协议,降低客户端和服务端代码耦合,也可以达到统一的鉴权和流控,然而此方式存在延时增加的风险,可能使 API 网关成为系统发展的瓶颈。

微服务架构是分布式服务架构,如何进行服务的注册和发现也是需要解决的问题。一种是通过客户端发现,调用方需要知道所有依赖服务的地址,开发成本较高,协议升级比较困难。另一种是通过统一网关发现具体服务的地址,对客户端来说实现比较简单,能够在网关进行统一鉴权和流控,要求网关高度可用性。

调用微服务尽可能做到有序,避免相互调用,杜绝循环调用。服务间要有清晰的层次关系,上层服务可以依赖下层服务,如果遇到下层服务需要同步消息给上层调用方的情况,可以考虑通过消息队列异步解耦,比如订单/审核系统在创建订单或者改变订单状态时,可以考虑使用双写(即写入数据库后,同时在消息队列也写一份),异构系统(比如订单执行系统)可以通过订阅消息保存异构数据。

个推在微服务上有哪些实践?

个推的服务场景主要有三种。其一是个推推送场景,通过 Java 语言开发,SOA 的架构方式来实现,保证信息推送的实时性与高并发性,这块微服务改造比较困难;其二是广告交易平台,比如投放平台、DMP 数据管理,以 Java 为主进行开发,对并发数要求较高,我们在逐步进行基于 Java 的微服务框架的微服务化尝试;其三是 web 业务系统,它为前端提供无状态的业务 API 接口,是典型的 request/response 方式,同时,这是我们目前微服务实践最多的场景。

随着业务快速发展,公司 web 相关的业务系统开发需求不断增加,这些系统都涉及到用户管理,后台管理,权限管理等。为进一步提高团队开发效率,我们对服务进行平台化、模块化改造,选择了如上的技术选型。

个推的整体架构如上图所示。请求先经过 LVS/HaProxy,到达基于 OpenResty 实现的 API 网关,API 网关会根据请求将流量 upstream 到服务单元。服务单元作为一个整体,支持通过 Lua、Node.js、Java 等语言实现业务逻辑,启动时向 Zookeeper 注册,API 网关会从 Zookeeper 获取服务单元部署信息。

服务单元如上图所示。它由 Openresty 统一对外暴露服务端,Openresty 内置了 lua 语言,可以在 weblua 框架中通过编写 lua 程序来进行业务逻辑处理。Openresty 通过 proxy_pass,upstream 将请求转给 webnode 处理,也可以在 Openresty 中通过配置处理 Java 业务逻辑。服务单元就像一个抽屉柜,具体的业务(app)就像一个抽屉,只要尺寸符合抽屉柜的要求,就能将抽屉推入到抽屉柜中,抽屉所用的语言不作要求。

Openresty 集成了 lua 脚本作为编程语言,使用 Zookeeper 服务注册。为了解决 lua 与 Zookeeper 不适配问题,在 Openresty 启动时启动 websocket 服务,Node.js 进程启动时同步启动 websocket 的 client,这样每个 Node.js 进程会和 Openresty 保持长连接和心跳,Openresty 会选择一个 Node.js 进程,启动 Zookeeperclient 完成服务注册。API 网关也是基于服务单元通过类似的方式实现完成服务注册的。

服务单元在 Openresty 层完成了统一鉴权,不会产生额外的性能开销。

我们可以用“通道化”来阐述服务间的调用问题。我们将微服务之间的调用比喻成水管,从水管的一端流进去的是请求信息,那么从另一端流出来的也应该是请求信息,我们只要求流入流出的信息保持一致,而不关心这些信息在传输过程中经过了转换或其他过程。如上图,A、B 之间的调用通过进程内 require 就能实现,而 A、C 间的调用是通过服务单元内的 http 完成的。

Q&A 环节

Q:微服务架构在运维部署是否会很麻烦?

A:随着微服务的不断推进,服务数量势必会越来越多,这就需要考虑 DEVOPS。比如代码提交之后通过 Jenkins 自动触发打包编译,自动生成版本号,进而触发自动测试部署和自动化测试,测试通过后进行一键部署升级、支持升级失败自动回滚等。我们目前已经实现了自动打包和测试部署,后续环节正在推进。

Q:Openresty 里对 Session 管理进行了处理,开发人员会不会觉得不方便?

A:在引入微服务框架之前,公司有很多独立业务服务,每个服务都有自己的账号系 统实现登录验证逻辑。虽然有现成的代码模块可以用,但每次都需要重新测试验证。如今,具体的业务服务都可以通过 Openresty 完成鉴权并统一对外,对开发和测试人员来说,反而减少了一定的工作量。

以上内容是俞锋锋 Qcon 大会的《基于 OpenResty 和 Node.js 的微服务架构实践》演讲的主要内容,如有问题,欢迎与我们留言探讨。

微服务需要很好的基础设施和自动化运维手段

OpenResty 看起来很性能爆炸好

dudu_zzzz 回复

然而能做的事情比较有限 让它承担的东西太多的话,可维护性又要大打折扣

这个怎么实现热重启呢?like nginx reload

需要 登录 后方可回复, 如果你还没有账号请 注册新账号