微服务1:微服务及其演进史
微服务2:微服务全景架构
微服务3:微服务拆分策略
微服务4:服务注册与发现
微服务5:服务注册与发现(实践篇)
微服务6:通信之网关
微服务7:通信之RPC
微服务8:通信之RPC实践篇(附源码)
上一节我们我们详细学习了RPC的概念和原理,以及它能够提供的能力。也对目前业内主流的RPC的框架有了一定的了解。接下来以Dobbo为例子,来学习下怎么使用RPC框架来进行服务之间的通信。
Apache Dubbo 是一款分布式微服务开发框架,它提供了 RPC通信 与 微服务治理 两大关键能力。这意味着,使用 Dubbo 开发的微服务,将具备相互之间的远程发现与通信能力, 同时利用 Dubbo 提供的丰富服务治理能力,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。同时 Dubbo 是高度可扩展的,用户几乎可以在任意功能点去定制自己的实现,以改变框架的默认行为来满足自己的业务需求。
服务发现,即消费端自动发现服务地址列表的能力,是微服务框架需要具备的关键能力,借助于自动化的服务发现,微服务之间可以在无需感知对端部署位置与 IP 地址的情况下实现通信。
实现服务发现的方式有很多种,Dubbo 提供的是一种 Client-Based 的服务发现机制,通常还需要部署额外的第三方注册中心组件来协调服务发现过程,如常用的 Nacos、Consul、Zookeeper 等,Dubbo 自身也提供了对多种注册中心组件的对接,用户可以灵活选择。
Dubbo 基于消费端的自动服务发现能力,其基本工作原理如下图:
Dubbo3 提供了 Triple(Dubbo3)、Dubbo2 协议,这是 Dubbo 框架的原生协议。除此之外,Dubbo3 也对众多第三方协议进行了集成,并将它们纳入 Dubbo 的编程与服务治理体系, 包括 gRPC、Thrift、JsonRPC、Hessian2、REST 等。
通过 Dubbo 定义的路由规则,实现对流量分布的控制,可以实现 A/B测试、金丝雀发布、蓝绿发布等能力。
描述 Dubbo 支持的配置,Dubbo 的动态配置能力,包含几大类: 启动阶段配置项、服务治理规则、动态配置项。
作为一个微服务框架,Dubbo sdk 跟随着微服务组件被部署在分布式集群各个位置,为了在分布式环境下实现各个微服务组件间的协作, Dubbo 定义了一些中心化组件,这包括:

Dubbo 通过 SPI 机制提供了非常灵活的可扩展性

首先引入 Zookeeper 和 Dubbo的依赖,Zookeeper的作用是注册与发现,Dubbo的作用是引入RPC通信核心能力
<!-- 包含了Zookeeper和Dubbo依赖 --> <dependency> <groupId>com.alibaba.boot</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>0.2.0</version> </dependency>父项目下面创建三个Module,一个通用模块,一个服务提供者模块,一个服务消费者模块

提供了公用的实体和接口,比如这边包含了一个用户信息的实体类和用户信息接口,后面的服务提供者和消费这都可以引用:
/** * @author brand * @Description: 用户信息实体 * @Copyright: Copyright (c) 2022 * @Company: Helenlyn, Inc. All Rights Reserved. * @date 2022/3/5 下午3:59 * @Update Time: * @Updater: * @Update Comments: */@Getter@Setterpublic class UserInfo implements Serializable { private Integer userId; private String userName; private Integer age; private String sex;}/** * @author brand * @Description: 用户信息接口 * @Copyright: Copyright (c) 2022 * @Company: Helenlyn, Inc. All Rights Reserved. * @date 2022/3/5 下午5:29 * @Update Time: * @Updater: * @Update Comments: */public interface UserInfoService { UserInfo getUserInfo (int userId) ; String getHello (int userId) ;}yml文件中的配置信息如下,可以看到我配置的zookeeper地址是127.0.0.1:2181,这是我本地部署到Zookeeper服务,大家可以对应修改下。
scan属性指的是暴露服务的位置,对应位置下的类,只要声明 Service 注解,就会被扫描并暴露出去。
# Dubbo Provider 配置dubbo: application: name: rpc-provider # 发布的dubbo服务名称 registry: address: 127.0.0.1:2181 # 使用Zookeeper注册中心提供的服务地址,这边可以配置多个,逗号隔开 protocol: zookeeper protocol: name: dubbo port: 20882 # 用dubbo协议在20882端口暴露服务 scan: # 使用注解方式暴露接口,扫描的位置 base-packages: rpcprovider.modules.service然后编写需要暴露出去的接口的实现,这边需要注意类上引入的注解为com.alibaba.dubbo.config.annotation的Service,
而不是springframework包中的service,这样Service服务才能被注册到dubbo中:
package rpcprovider.modules.service;import com.alibaba.dubbo.config.annotation.Service;import rpccommon.dto.UserInfo;import rpccommon.service.UserInfoService;/** * @author brand * @Description: * @Copyright: Copyright (c) 2022 * @Company: Helenlyn, Inc. All Rights Reserved. * @date 2022/3/5 下午5:43 * @Update Time: * @Updater: * @Update Comments: */@Servicepublic class UserInfoServiceImpl implements UserInfoService { @Override public UserInfo getUserInfo(int userId) { UserInfo userInfo = new UserInfo(); userInfo.setUserId(userId); userInfo.setAge(18); userInfo.setSex("男"); userInfo.setUserName("Brand"); return userInfo; } @Override public String getHello(int userId) { return " Hello, " + userId; }}启动起来看看Zookeeper的效果,是不是被注册到Dubbo中,这边可以用看到,Provider中已经有注册节点了。
[zk: 127.0.0.1:2181(CONNECTED) 68] ls /[dubbo, zookeeper][zk: 127.0.0.1:2181(CONNECTED) 69] ls /dubbo[rpccommon.service.UserInfoService][zk: 127.0.0.1:2181(CONNECTED) 70] ls /dubbo/rpccommon.service.UserInfoService[configurators, consumers, providers, routers][zk: 127.0.0.1:2181(CONNECTED) 71] ls /dubbo/rpccommon.service.UserInfoService/providers[dubbo%3A%2F%2F172.21.213.159%3A20882%2Frpccommon.service.UserInfoService%3Fanyhost%3Dtrue%26application%3Drpc-provider%26dubbo%3D2.6.2%26generic%3Dfalse%26interface%3Drpccommon.service.UserInfoService%26methods%3DgetHello%2CgetUserInfo%26pid%3D60138%26side%3Dprovider%26timestamp%3D1646535565910][zk: 127.0.0.1:2181(CONNECTED) 72] yml文件中的配置信息如下:
# Dubbo Consumer 配置文件dubbo: application: name: rpc-consumer registry: address: 127.0.0.1:2181 # 使用Zookeeper注册中心提供的服务地址来获取服务,这边可以多个逗号隔开 protocol: zookeeper消费者使用注解方式进行RPC调用,这边注意,通过@Reference注解, dubbo会在扫描的时候自动帮我们代理接口,然后通过rpc调用远程服务。如下:
package rpcconsume.modules.service;import com.alibaba.dubbo.config.annotation.Reference;import org.springframework.stereotype.Service;import rpccommon.dto.UserInfo;import rpccommon.service.UserInfoService;/** * @author brand * @Description: 消费者使用注解方式进行RPC调用 * @Copyright: Copyright (c) 2022 * @Company: Helenlyn, Inc. All Rights Reserved. * @date 2022/3/5 下午6:49 * @Update Time: * @Updater: * @Update Comments: */@Servicepublic class UserInfoConsumer implements UserInfoService { @Reference private UserInfoService userInfoService ; @Override public UserInfo getUserInfo(int userId) { return userInfoService.getUserInfo(userId); } @Override public String getHello(int userId) { return userInfoService.getHello(userId); }}写一个Controller,通过外部调用,来测试效果
package rpcconsume.modules.controller;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RestController;import rpccommon.dto.UserInfo;import rpcconsume.modules.service.UserInfoConsumer;/** * @author brand * @Description: 测试消费者效果 * @Copyright: Copyright (c) 2022 * @Company: Helenlyn, Inc. All Rights Reserved. * @date 2022/3/5 下午6:48 * @Update Time: * @Updater: * @Update Comments: */@RestController@Slf4j@RequestMapping("/v1.0/consumer")public class ConsumerController { @Autowired private UserInfoConsumer userInfoConsumer ; /** * 获取用户信息 * @return */ @RequestMapping(value = "/userinfo/{user_id}", method = RequestMethod.GET) public UserInfo getUserInfo(@PathVariable("user_id") int userId) { return userInfoConsumer.getUserInfo(userId); } /** * 获取问候信息 * @return */ @RequestMapping(value = "/hello/{user_id}", method = RequestMethod.GET) public String getHello(@PathVariable("user_id") int userId) { return userInfoConsumer.getHello(userId); }}查一下Zookeeper 上的消费者信息:
[zk: 127.0.0.1:2181(CONNECTED) 73] ls /dubbo/rpccommon.service.UserInfoService/consumers[consumer%3A%2F%2F172.21.213.159%2Frpccommon.service.UserInfoService%3Fapplication%3Drpc-consumer%26category%3Dconsumers%26check%3Dfalse%26dubbo%3D2.6.2%26interface%3Drpccommon.service.UserInfoService%26methods%3DgetHello%2CgetUserInfo%26pid%3D60884%26side%3Dconsumer%26timestamp%3D1646536367371]调用效果:
GitHub地址:https://github.com/WengZhiHua/Helenlyn.Grocery/tree/master/parent
RPC通信只是 Dubbo 功能的一部分,像上面介绍的那样,除了RPC通信之外,还有服务注册与发现、配置管理、服务流量治理等,基本能达到一个微服务的基本能力要求。
另外我们还看到,除了Dubbo之外,百度的brpc和Google的gRPC也有很大的受众,也是不错的选择,我们上一章有对主流RPC框架做了对比和分析,可以根据自身的业务特性进行技术选型。
