请求驱动
请求驱动,也就是支持基于请求的动态弹性伸缩并且简化请求处理逻辑。有些同学可能把这个模型称之为 Event-driven,也就是事件驱动,但是请求驱动实际是事件驱动中的一个分支。
什么是请求驱动呢?从传统的微服务架构看,当一个外部系统请求进来后,一般都会经过一个 L4/L7 的负载均衡,然后给到不同的微服务实例上面。在同一个微服务实例本身进程的内部,一般会有两块逻辑,第一块逻辑是请求管理,它可能是一个 HTTP Server 和一些 Handlers,有一些队列管理、请求分发等能力。这些请求最终会提交到第二个逻辑部分,processor 也就是真正的请求业务处理逻辑中,真正的处理并且相应这些请求。
这个架构会带来两个问题:
- 请求管理的逻辑在不同的微服务框架实现中都要去写一遍,比如 Java、Go 或 Python 都要有自己的请求管理逻辑。
- 请求管理和请求处理形成耦合关系。因此,在这个架构下不存在一个全局独立的可以感知请求以及进行流量管理的控制层。只有到了微服务实例自身的处理层,才能解析这个请求。这时候即便这个微服务实例已经过载,也很难把请求再转发给其他微服务实例进行负载均衡了。
请求驱动系统就是尝试去解决这两个问题,我们尝试在微服务中做一个请求驱动的解耦操作。
首先把外部系统传输过来的请求都进行一次标准化,我们有一个适配器,进行标准化之后,把它放到一个请求负载均衡器中,这个负载均衡已经能理解请求本身的语义,它就能驱动请求处理的逻辑进行请求处理。当请求处理单元不够时,可以通过请求处理的管理器进行扩容;当请求处理的逻辑单元比较多时,还可以进行缩容,这样就可以节约成本。另外,开发人员也不用再去实现请求管理逻辑,降低了开发成本。
刚才讲的请求驱动模型可以分为三部分:
- 请求的标准化
- 请求的路由
- 请求的处理
其实,如果把外部系统的请求标准化,加上请求路由、处理管理,而不包含业务代码,就会组成我们常说 Serverless 概念。这也就是一种把微服务体系和平台化的 Serverless 体系融合的一个过程。
Serverless 平台有阿里云 FaaSS、SAE,AWS 有 Lambda、Google 推出了 CloudRun、Azure 有 Functions。如果大家希望自己能够构建一个 Serverless 平台,如请求标准化,也有像 Cloud Events 这样的开源请求标准, Knative 这样的处理路由以及处理请求的水平扩展能力组件,可以利用 Kafka 或者 RocketMQ 来做请求本身的持久化以及请求本身的转发。
分布式运行时在编程模型中的分布式运行时,也就是我们希望微服务能够有更好的多语言环境支持、环境可移植性并能做到极速启动。
单体应用时代,我们的业务代码跟中间件代码耦合在一起,而且是一份部署的实例;当到了微服务时代,通过像 Service Mesh 服务网格进行流量管理之后,可以看到我们的业务代码和流量管理代码实际上是可分离的,只有部分中间件的代码仍然和部分业务代码耦合在一起形成一个二进制。
为了能够做到充分的多语言能力支持、环境的可移植性,我们希望能够把剩余的中间件代码也从业务中解耦出来,这项技术叫做运行时解耦。它的根本理念是通过向业务代码提供一个标准的可扩展 API,并且是一个多语言可支持、轻量级的 API,通过调用 API 来实现中间件的功能,我们把中间件的能力像流量管理一样下沉到一个 Sidecar 中,用一种语言进行统一实现,然后设计一个可拔插的模式,让大家能够拔插更多中间件的能力。
这项技术比较领先的一个实践是微软去年推出的一个分布式运行时,叫做 Dapr。
Dapr 向业务的代码暴露了两个 API,一个是 HTTP 的 API,另外一个是 grpc 的 API。这两个 API 都非常轻量级,并能够跨多种语言,Dapr 本身作为分布式运行时,可以对接多种中间件系统,向上通过标准的 API 屏蔽不同系统之间的差异性,提供一定的编程界面界面统一。代码实现上把中间件的代码从应用级别抽离到 Sidecar 中,如上图所示,我们在业务上面只需要写业务的代码,其他代码几乎都被基于 Dapr 的平台所接管。
Dapr 本身分为两部分:第一部分是 Dapr 向 Application 暴露的 API,另一部分是 Dapr 的框架层。
通过 Dapr 的框架层,我们可以接入各种不同的 Dapr 相关实现:Resource bandings 如 Kafka/SQS、管理数据的如 Redis/cassandra、或者我们去做 Publish & subscribe 如 RabbitMQ、甚至 Distributed Tracing 如 Prometheus/Open tracing 等等,都可以接入到 Dapr 这套框架里,然后通过统一的标准 HTTP、gRPC API 提供给业务代码、应用代码去使用,这样就做到了业务代码与中间件、流量管理能力的更彻底的解耦,应用的开发人员也能够更专注、更自由地去关注业务代码研发。