Apache Dubbo 是一款微服务开发框架,它提供了 RPC通信 与 微服务治理 两大关键能力。这意味着,使用 Dubbo 开发的微服务,将具备相互之间的远程发现与通信能力, 同时利用 Dubbo 提供的丰富服务治理能力,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。同时 Dubbo 是高度可扩展的,用户几乎可以在任意功能点去定制自己的实现,以改变框架的默认行为来满足自己的业务需求。
1.简介
Apache Dubbo 是一款微服务开发框架,它提供了 RPC通信 与 微服务治理 两大关键能力。这意味着,使用 Dubbo 开发的微服务,将具备相互之间的远程发现与通信能力, 同时利用 Dubbo 提供的丰富服务治理能力,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。同时 Dubbo 是高度可扩展的,用户几乎可以在任意功能点去定制自己的实现,以改变框架的默认行为来满足自己的业务需求。
Dubbo3 基于 Dubbo2 演进而来,在保持原有核心功能特性的同时, Dubbo3 在易用性、超大规模微服务实践、云原生基础设施适配、安全设计等几大方向上进行了全面升级。 以下文档都将基于 Dubbo3 展开。
2.ZooKeeper
安装 ZooKeeper
到 https://archive.apache.org/dist/zookeeper/stable/ 下载 ZooKeeper,目前的最新版是 3.5.6。
把 apache-zookeeper-3.5.6-bin.tar.gz 解压到一个本地目录 (目录名最好不要包含空格和中文)。我使用 /usr/local 目录。
1
| tar -zxvf apache-zookeeper-3.8.4-bin.tar.gz
|
把 conf 目录下的 zoo_sample.cfg 重命名为 zoo.cfg,然后修改配置。
cp zoo_sample.cfg zoo.cfg
mkdir zoodata
1 2 3 4 5 6 7 8 9 10
| # 心跳检查的时间 2秒 tickTime=2000dd # 初始化时 连接到服务器端的间隔次数,总时间10*2=20秒 initLimit=10 # ZK Leader 和follower 之间通讯的次数,总时间5*2=10秒 syncLimit=5 # 存储内存中数据快照的位置,如果不设置参数,更新事务日志将被存储到默认位置。 dataDir=/root//root/apache-zookeeper-3.8.4-bin/zoodata # ZK 服务器端的监听端口 clientPort=2181
|
配置以下环境变量 vim /etc/profile
:
1 2
| export ZOOKEEPER_HOME=/root/apache-zookeeper-3.8.4-bin export PATH=$PATH:$ZOOKEEPER_HOME/bin:$ZOOKEEPER_HOME/conf
|
source /etc/profile
启动 Zookeeper
再安装配置完成后,就可以启动 Zookeeper,使用 zkServer.sh start 启动 ZooKeeper 服务:
1 2 3 4 5
| [root@wupx apache-zookeeper-3.5.6-bin]# ./zkServer.sh start /usr/bin/java ZooKeeper JMX enabled by default Using config: /usr/local/apache-zookeeper-3.5.6-bin/bin/../conf/zoo.cfg Starting zookeeper ... STARTED
|
查看状态 ./zkServer.sh status
停止zookeeper ./zkServer.sh stop
3.使用Dubbo
新建Spring和SpringMvc的项目
1.引入依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| <properties> <spring.version>5.1.9.RELEASE</spring.version> <dubbo.version>2.7.4.1</dubbo.version> <zookeeper.version>4.0.0</zookeeper.version> </properties>
<dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency>
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.33</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.33</version> </dependency>
<dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> <version>${dubbo.version}</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>${zookeeper.version}</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>${zookeeper.version}</version> </dependency> </dependencies>
|
2.配置文件
在resources目录下创建Soring.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://dubbo.apache.org/schema/dubbo" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- <context:component-scan base-package="com.richu.service"/> --> <!--项目名--> <dubbo:application name="dubbo-server"/> <!--注册中心地址--> <dubbo:registry address="zookeeper://192.168.3.133:2181"/> <!--包扫描--> <dubbo:annotation package="com.richu.service"/> </beans>
|
在webapp/WEB-INF/创建web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:Spring.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app>
|
添加注解
1 2 3 4 5 6 7
| @DubboService public class UserServiceImpl implements UserService { @Override public String login(String username, String password) { return "test login"; } }
|
3.SpringBoot使用Dubbo
User类:
1 2 3 4 5 6 7
| @Data public class User implements Serializable { private static final long serialVersionUID = -9206514891359830486L; private int id; private String name; private String sex; }
|
UserService:
1 2 3
| public interface UserService { User getUser(int id); }
|
新建两个SpringBoot项目,一个是服务提供者,一个是服务消费者,引入dubbo的核心依赖
这里排除一下zookeeper的依赖,使用自己的zookeeper版本选择自己的依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2.7.4.1</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>4.0.0</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>4.0.0</version> <exclusions> <exclusion> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.14</version> </dependency>
|
这里的配置都写在application.yaml中,首先是服务提供者:
1 2 3 4 5 6 7 8
| dubbo: application: name: dubbo-provider registry: address: zookeeper://127.0.0.1:2181 protocol: name: dubbo port: 20880
|
服务提供者需要写服务的实现类,这里需要注意@Service注解采用的是dubbo包下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import org.apache.dubbo.config.annotation.Service; import org.springframework.stereotype.Component;
@Service @Component public class UserServiceImpl implements UserService { @Override public User getUser(int id) { User user=new User(); user.setId(id); user.setName("javayz"); user.setSex("man"); return user; } }
|
接着在启动类上添加一个@EnableDubbo注解即可。
服务的消费者同样是先写一下配置文件:
1 2 3 4 5
| dubbo: application: name: dubbo-consumer registry: address: zookeeper://127.0.0.1:2181
|
UserController
接着通过@Reference注解将service对象引进来
1 2 3 4 5 6 7 8 9 10 11 12
| @RestController @RequestMapping("/user") public class UserController {
@Reference private UserService userService;
@GetMapping("/{id}") public User getUser(@PathVariable int id) { return userService.getUser(id); } }
|
http://localhost:8081/user/1
返回结果
1 2 3 4 5
| { "id": 1, "name": "hello", "sex": "man" }
|
4.安装dubbo-admin
https://github.com/apache/dubbo-admin 下载并解压,需要有maven和node
mvn clean package 打包 或使用mvn clean package -Dmaven.test.skip=true
打包后用java -jar执行 (推荐使用java8或11)
在ui模块 node可以使用ui模块node文件夹下的node.exe
npm run dev 启动前端 http://localhost:38082/
4.Dubbo高级特性
重试和超时
1
| @Service(timeout = 5000,retries = 10)
|
多版本
1 2 3 4 5 6
| @Service(timeout = 5000,retries = 10,version = "v2.0") @Service(timeout = 5000,retries = 10,version = "v1.0")
@Reference(version = "v1.0") private UserService userService;
|
dubbo负载均衡策略
https://cn.dubbo.apache.org/zh-cn/overview/what/core-features/load-balance/
1 2 3 4
| @Service(weight = 100) @Service(weight = 200) @Service(weight = 300)
|
全局配置
Dubbo 框架的默认策略是 random
加权随机负载均衡。如果要调整策略,只需要设置 loadbalance
相应取值即可,每种负载均衡策略取值请参见文档最上方表格。
为所有服务调用指定全局配置:
1 2 3
| dubbo: consumer: loadbalance: roundrobin
|
接口级配置
可以为每个服务指定不同的负载均衡策略。
在 provider 端设置,作为 consumer 侧默认值
1 2
| @DubboService(loadbalance = "roundrobin") public class DemoServiceImpl implements DemoService {}
|
在 consumer 端设置,具备更高优先级
1 2
| @DubboReference(loadbalance = "roundrobin") private DemoService demoService;
|
方法级配置
也可以指定方法(method)级别的负载均衡策略。
在 Spring Boot 开发模式下,配置 method 级别参数有以下几种方式:
JavaConfig
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @Configuration public class DubboConfiguration { @Bean public ServiceBean demoService() { MethodConfig method = new MethodConfig(); method.setName("sayHello"); method.setLoadbalance("roundrobin");
ServiceBean service = new ServiceBean(); service.setInterface(DemoService.class); service.setRef(new DemoServiceImpl()); service.addMethod(method) return service; } } @Autowire private DemoService demoService;
@Configuration public class DubboConfiguration { @Bean public ReferenceBean demoService() { MethodConfig method = new MethodConfig(); method.setName("sayHello"); method.setLoadbalance("roundrobin");
ReferenceBean<DemoService> reference = new ReferenceBean<>(); reference.setInterface(DemoService.class); reference.addMethod(method); return reference; } }
|
dubbo.properties
1
| dubbo.reference.org.apache.dubbo.samples.api.DemoService.sayHello.loadbalance=roundrobin
|
一致性哈希配置
默认采用第一个参数作为哈希 key,如果需要切换参数,可以指定 hash.arguments
属性
1 2 3 4 5 6 7 8
| ReferenceConfig<DemoService> referenceConfig = new ReferenceConfig<DemoService>();
Map<String, String> parameters = new HashMap<String, String>(); parameters.put("hash.arguments", "1"); parameters.put("sayHello.hash.arguments", "0,1"); referenceConfig.setParameters(parameters); referenceConfig.setLoadBalance("consistenthash"); referenceConfig.get();
|
dubbo限流策略配置
限制服务器端并发执行数(服务粒度)
限制 com.richuff.UserService
的每个方法,服务器端并发执行(或占用线程池线程数)不能超过 10 个
1 2
| @DubboService(executes=10) private UserServiceImpl implements UserService{}
|
限制服务器端并发执行数(方法粒度)
限制 com.richuff.UserService
的 sayHello
方法,服务器端并发执行(或占用线程池线程数)不能超过 10 个
1 2
| @DubboService(executes=10, methods = {@Method(name="sayHello",executes=10)}) private UserServiceImpl implements UserService{}
|
限制消费端并发调用数(服务粒度)
限制 com.richuff.UserService
的每个方法,每客户端并发执行(或占用连接的请求数)不能超过 10 个
1 2
| @DubboReference(actives=10) private UserService userService;
|
限制消费端并发调用数(方法粒度)
限制 com.richuff.UserService
的 sayHello
方法,每客户端并发执行(或占用连接的请求数)不能超过 10 个
1 2
| @DubboReference(actives=10, methods = {@Method(name="sayHello",executes=10)}) private UserService userService;
|
集群容错模式
可以自行扩展集群容错策略,参见:集群扩展
Failover Cluster
失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries="2"
来设置重试次数(不含第一次)。
重试次数配置如下:
1
| <dubbo:service retries="2" />
|
或
1
| <dubbo:reference retries="2" />
|
或
1 2 3
| <dubbo:reference> <dubbo:method name="findFoo" retries="2" /> </dubbo:reference>
|
Failfast Cluster
快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。
Failsafe Cluster
失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。
Failback Cluster
失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
Forking Cluster
并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2"
来设置最大并行数。
Broadcast Cluster
广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。
现在广播调用中,可以通过 broadcast.fail.percent 配置节点调用失败的比例,当达到这个比例后,BroadcastClusterInvoker 将不再调用其他节点,直接抛出异常。 broadcast.fail.percent 取值在 0~100 范围内。默认情况下当全部调用失败后,才会抛出异常。 broadcast.fail.percent 只是控制的当失败后是否继续调用其他节点,并不改变结果(任意一台报错则报错)。broadcast.fail.percent 参数 在 dubbo2.7.10 及以上版本生效。
Broadcast Cluster 配置 broadcast.fail.percent。
broadcast.fail.percent=20 代表了当 20% 的节点调用失败就抛出异常,不再调用其他节点。
1
| @reference(cluster = "broadcast", parameters = {"broadcast.fail.percent", "20"})
|