Dubbo 在 2011 年开源之后,被大量的中小型公司采用;
在 Spring Boot 推出之后,Spring 逐渐焕发出第二春,随即 Spring Cloud 面世,逐渐占领市场,在中国市场中,和 Dubbo 分庭抗争;
gRPC 是 Google 推出的基于 Http2 的端到端的通信工具,逐渐在 K8s 市场上占据统治地位,如 etcd,Istio 等都采用 gRPC 作为通信工具;
Service Mesh 从开始概念上就火热,现在逐渐走向成熟;
Istio + Envoy (其他 sidecar )逐渐开始走上舞台。
应用开发者视角
从功能层面来说,对开发者有感知的功能有:
服务实现
服务暴露(注解或配置)
服务调用(注解或配置)
服务治理等
从选型角度会关注以下几点:
易用性(开发易用性和开箱即用)
性能
功能
扩展性等
框架开发者视角
关键流程:
服务暴露
服务注册
服务发现
服务调用
服务治理
关键知识点:
序列化
网络通信
服务路由
负载均衡
服务限流
熔断
降级等服务治理
主流技术实现
Dubbo / HSF
Dubbo 提供了面向接口的远程方法调用。应用开发者定义接口,编写服务并暴露;
Client 端通过接口进行调用;
Dubbo 注册服务的维度是接口维度,每个接口会在注册中心写入一条数据;
Dubbo 支持条件路由,脚本路由,Tag 路由等。这些路由规则都是强依赖于 IP 地址。
备注:Dubbo 和 HSF 的大部分机制都是相似的,所以下面都以 Dubbo 作为方案进行讨论。
SpringCloud
Spring Cloud 通过 Rest 形式进行网络调用。应用开发者可以自己编写暴露 Rest 服务,如 springmvc 。
Spring Cloud 里的服务注册是应用维度( Eureka ),Client 端和 Server 端通过约定的方式进行通信。
Spring Cloud 提供了一套标准 API ,而其中 Netflix 是其中的佼佼者,对这套 API 进行了实现,对大部分开发者来说,可以回直接依赖和使用 Netflix ,所以可以说是 Netflix 提供成了 Spring Cloud 的核心。但是作为商业公司对开源投入往往会多变,如 Eureka 已经体制维护。
K8s 体系的默认情况下, Pod 的 IP 是变化的,所以 Pod 和 Pod 之间需要通信的话,有几种方式:
Service+DNS:新建一个 Service ,可以通过标签选择到一组 Pod 列表,这个 Service 对应一个不变的集群 IP ;Client 端通过 DNS 方式或者直接访问集群 IP。这个集群 IP ,约等于实现了负载均衡 ( iptable 方式);
headless service:headless service 和上面的 service 的区别是,它不提供集群 IP ,通过主机名的形式获取一组 IP 列表,Client 端自己决定访问哪个 Pod。
Istio + Envoy
Istio 的控制层会向 K8s 的 Api server 请求并监听 pod 信息,service 信息等信息。这样 Istio 中就有了完整的 K8s 集群中的 pod,service 等的完整信息。如果 K8s 集群中有信息变更,Istio 中也可以得到通知并更新对应的信息。
Dubbo 原有体系里的服务治理是强依赖于 IP ,当配置了一套服务治理规则的时候,最后都是基于一个或多个 IP 地址。
到 K8s 体系下之后,要考虑的是 Pod 的 IP 不是固定的。所以当前的路由规则不能满足条件,而且会产生很多规则垃圾数据。K8s 体系下,通过 service 查找 Pod ,是基于 label selector ;通过 deployment 管理 Pod ,其实也是基于 Pod label selector 。所以 pod label selector 是在 K8s 习题中比较通用的解决方案。
以路由规则为例,需要支持一种新的路由规则:label 路由。通过一定条件匹配之后,将结果定位到以 label selector 查询到的 Pod 列表里,而非原来的 ip 列表。
要支持 label 路由,client 端需要获取到 client 端自己的 Pod label 信息,还需要获取到 server pod 列表中每个 Pod 的 label 信息。
应用获取当前 Pod 的信息方式
Pod 定义环境变量,应用获取;Dubbo 提供对环境变量读取的支持,Pod 中需要按照 Dubbo 定义的环境变量设置具体的 pod 信息。
通过 Downward API 传递 Pod 信息;Dubbo 需要提供对 Downward 的目录读取,Pod 中需要定制 downward 的对应配置。
通过 API Server 获取数据;最强大的方式,但是应用需要强依赖于 API Server 。
应用获取其他 Pod 的信息方式
通过调用其他 Pod 的服务获取;依赖于应用能获取自身的 Pod 信息,同时将自身的 Pod 信息暴露成服务( rest 或 dubbo 协议)。client 端通过调用对用的 Pod 获取到对应 Pod 的完整信息。
通过 Api server 获取数据;很强大,但增加了对 Api server 的依赖。
服务注册和发现
K8s 体系下,RPC 服务发现有以下几种方式:
注册机制:将 IP 写入注册中心,用心跳保持连接;当心跳停止,从注册中心删除;
利用 Service+DNS :新建一个 Service ,可以通过标签选择到一组 Pod 列表,这个 Service 对应一个不变的集群 IP ;Client 端通过 DNS 方式或者直接访问集群 IP 。这个集群 IP ,约等于实现了负载均衡 ( iptable 方式);
利用 headless service(DNS) :headless service 和上面的 service 的区别是,它不提供集群 IP ,通过主机名的形式获取一组 IP 列表,Client 端自己决定访问哪个 Pod ;
api server :Client 端直接请求 api server ,获取到 pod 的列表, Client 自己决定访问 pod 的逻辑。同时获取的时候增加 watch ,api server 会将 pod 的变化信息同步 Client 。
通过拿到 Server 端的 IP 或者 host ,Client 端就可以发起 http 或者其他协议的请求。
3. Dubbo + Api Server
Pod 的容器中部署的 Dubbo 应用,服务注册流程可以直接删除,服务发现功能通过和 Api Server 进行交互,获取 Pod 和 service 信息,同时 watch pod 和service 的变更。通过这种方式之后,服务治理相关的信息也可以通过 Api Server 直接获取。