• Dubbo应用与实践


    微服务架构中,比较主流的通信组件:

    • Spring Cloud中的OpenFeign
    • Dubbo
    • Thrift,轻量级、跨语言的远程服务调用框架,最初由Facebook开发,后面进入Apache开源项目。通过自身的IDL中间语言,并借助代码生成引擎生成各种主流语言的RPC服务端/客户端模板代码。

    它们都统称为RPC框架

    RPC协议与RPC框架

    RPC(Remote Procedure Call)即远程过程调用,它是一个计算机通信协议,这个协议允许两个跨网络节点的进程进行通信,让我们能够像调用本地服务一样调用远程服务。

    RPC协议定义了一种通信的标准规范,为了满足不同场景需求,于是很多RPC框架在这个协议基础上应运而生。而Dubbo就是主流RPC框架之一。

    Dubbo

    Dubbo背景

    Dubbo是Alibaba内部使用的一个分布式服务治理框架,很多公司在应用dubbo时,会根据自身业务特性进行优化改进,从而衍生出了很多版本,比如京东的JSF,新浪的Motan,当当的dubbox。

    主要分2.x和3.x两个版本。3.x定义为面向云原生的下一代RPC服务框架,目前还是以2.7.x版本为主。

    Dubbo特性/功能

    Dubbo之所以能够被很多公司应用,是因为随着服务化快速发展,远程通信带来了很多弊端,比如:

    1. 服务链路变长了,如何实现对服务链路的跟踪和监控?
    2. 服务大规模集群,使得服务之间需要依赖第三方注册中心来解决服务之间的发现
    3. 服务间通信异常,需要一种保护机制防止一个节点故障引发大规模系统故障,所以需要容错机制
    4. 服务大规模集群,客户端需要引入负载均衡策略实现请求分发

    传统RPC无法很好的解决这些问题,而Dubbo都能支持这些。

    所以Dubbo不仅仅是一个RPC框架,更是一个成熟的微服务框架。它包含一下功能:

    1. RPC框架,提供高性能的基于代理的RPC调用,服务以接口为粒度,为开发者屏蔽远程调用底层细节;
    2. 智能负载均衡,内置多种负载均衡策略,智能感知下游节点健康状况,减少调用延迟,提高系统吞吐量;
    3. 服务注册与发现,支持多种注册中心服务,服务实例上下线实时感知;
    4. 可视化的服务治理与运维,提供丰富的服务治理、运维工具;可随时查询服务元数据、服务健康状态及调用统计,实时下发路由策略、调用配置参数;
    5. 高度可扩展能力,遵循微内核+插件的设计原则;

    Dubbo架构图

    节点角色说明:

    • Provider: 暴露服务的服务提供方。
    • Consumer: 调用远程服务的服务消费方。
    • Registry: 服务注册与发现的注册中心。
    • Monitor: 统计服务的调用次调和调用时间的监控中心。
    • Container: 服务运行容器。

    调用关系说明:

    • 0. 服务容器负责启动,加载,运行服务提供者。
    • 1. 服务提供者在启动时,向注册中心注册自己提供的服务。
    • 2. 服务消费者在启动时,向注册中心订阅自己所需的服务。
    • 3. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
    • 4. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
    • 5. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
       

     新版本Dubbo,多了配置中心和元数据中心

    Dubbo应用实践

    dubbo + spring boot

    1. pom引入zk和dubbo-spring-boot-starter
    2. application.properties中配置bubbo service名称、dubbo协议、注册中心地址
    3. 在项目启动类上添加@EnableDubbo
    4. 在service上添加@DubboService
    5. 引用的地方加@DubboReference调用service

    定义service api

    coupon-service-api

    1. public interface ICouponService {
    2. // 查询有效的优惠券列表
    3. String selectValidCoupons();
    4. }

    user-service-api

    1. public interface IUserService {
    2. // 查询当前用户能够领取的优惠券列表
    3. String selectValidTemplates();
    4. }

    定义service api provider

    coupon-service-provider

    pom.xml

    1. <dependency>
    2. <artifactId>coupon-service-apiartifactId>
    3. <groupId>org.normal.examplegroupId>
    4. <version>1.0-SNAPSHOTversion>
    5. dependency>
    6. <dependency>
    7. <groupId>org.apache.dubbogroupId>
    8. <artifactId>dubbo-dependencies-zookeeperartifactId>
    9. <type>pomtype>
    10. <version>2.7.15version>
    11. dependency>
    12. <dependency>
    13. <groupId>org.apache.dubbogroupId>
    14. <artifactId>dubbo-spring-boot-starterartifactId>
    15. <version>2.7.15version>
    16. dependency>

    启动类上通过@EnableDubbo让spring扫描dubbo注解

    1. @EnableDubbo
    2. @SpringBootApplication
    3. public class CouponServiceProviderApplication {
    4. public static void main(String[] args) {
    5. SpringApplication.run(CouponServiceProviderApplication.class, args);
    6. }
    7. }

    通过@DubboService注册dubbo服务

    1. @DubboService
    2. public class CouponService implements ICouponService {
    3. @Override
    4. public String selectValidCoupons() {
    5. // TODO 实现数据查询,并且返回
    6. return "返回有效优惠券列表";
    7. }
    8. }

    src/main/resources/application.properties

    1. # 应用名称
    2. spring.application.name=coupon-service-provider
    3. dubbo.application.name=coupon-service
    4. # 配置-1代表随机分配端口
    5. dubbo.protocol.port=-1
    6. dubbo.protocol.name=dubbo
    7. dubbo.registry.id=zk-registry
    8. dubbo.registry.address=zookeeper://192.168.1.101:2181?timeout=20000
    9. dubbo.config-center.address=zookeeper://192.168.1.101:2181?timeout=20000
    10. dubbo.metadata-report.address=zookeeper://192.168.1.101:2181?timeout=20000

    user-service-provider

    pom.xml

    1. <dependency>
    2. <groupId>org.normal.usergroupId>
    3. <artifactId>user-service-apiartifactId>
    4. <version>1.0-SNAPSHOTversion>
    5. dependency>
    6. <dependency>
    7. <artifactId>coupon-service-apiartifactId>
    8. <groupId>org.normal.examplegroupId>
    9. <version>1.0-SNAPSHOTversion>
    10. dependency>
    11. <dependency>
    12. <groupId>org.apache.dubbogroupId>
    13. <artifactId>dubbo-dependencies-zookeeperartifactId>
    14. <type>pomtype>
    15. <version>2.7.15version>
    16. dependency>
    17. <dependency>
    18. <groupId>org.apache.dubbogroupId>
    19. <artifactId>dubbo-spring-boot-starterartifactId>
    20. <version>2.7.15version>
    21. dependency>

    启动类上通过@EnableDubbo让spring扫描dubbo注解

    1. @EnableDubbo
    2. @SpringBootApplication
    3. public class UserServiceProviderApplication {
    4. public static void main(String[] args) {
    5. SpringApplication.run(UserServiceProviderApplication.class, args);
    6. }
    7. }

    通过@DubboService注册dubbo服务,通过@DubboReference注解发现dubbo服务

    1. @DubboService
    2. public class UserService implements IUserService {
    3. @DubboReference //
    4. ICouponService couponService;
    5. @Override
    6. public String selectValidTemplates() {
    7. // 1. 查询当前用户已经领取过的优惠券
    8. // 2. 查询优惠券服务,获取当前可以领取的有效优惠券列表
    9. String list=couponService.selectValidCoupons();
    10. return "用户服务返回:可以领取的优惠券列表,加载到的可领取优惠券:"+list;
    11. }
    12. }

    src/main/resources/application.properties

    1. # 应用名称
    2. spring.application.name=user-service-provider
    3. dubbo.application.name=user-service
    4. # 配置-1代表随机分配端口
    5. dubbo.protocol.port=-1
    6. dubbo.protocol.name=dubbo
    7. dubbo.registry.id=zk-registry
    8. dubbo.registry.address=zookeeper://192.168.1.101:2181?timeout=20000
    9. dubbo.config-center.address=zookeeper://192.168.1.101:2181?timeout=20000
    10. dubbo.metadata-report.address=zookeeper://192.168.1.101:2181?timeout=20000

    调用方coupon-portal

    pom.xml

    1. <dependency>
    2. <groupId>org.springframework.bootgroupId>
    3. <artifactId>spring-boot-starter-webartifactId>
    4. <version>2.3.7.RELEASEversion>
    5. dependency>
    6. <dependency>
    7. <groupId>org.normal.usergroupId>
    8. <artifactId>user-service-apiartifactId>
    9. <version>1.0-SNAPSHOTversion>
    10. dependency>
    11. <dependency>
    12. <groupId>org.apache.dubbogroupId>
    13. <artifactId>dubbo-spring-boot-starterartifactId>
    14. <version>2.7.15version>
    15. dependency>
    16. <dependency>
    17. <groupId>org.apache.dubbogroupId>
    18. <artifactId>dubbo-dependencies-zookeeperartifactId>
    19. <type>pomtype>
    20. <version>2.7.15version>
    21. dependency>

    启动类

    1. @EnableDubbo
    2. @SpringBootApplication
    3. public class CouponPortalApplication {
    4. public static void main(String[] args) {
    5. SpringApplication.run(CouponPortalApplication.class, args);
    6. }
    7. }

    controller层通过@DubboReference发现dubbo service服务

    1. @RestController
    2. public class UserController {
    3. @DubboReference
    4. IUserService userService;
    5. @GetMapping("/coupon")
    6. public String validCoupons(){
    7. return userService.selectValidTemplates();
    8. }
    9. }

    resources/application.properties

    1. # 应用名称
    2. spring.application.name=coupon-portal
    3. # 应用服务 WEB 访问端口
    4. server.port=8080
    5. dubbo.application.name=coupon-portal
    6. dubbo.registry.id=zk-registry
    7. dubbo.registry.address=zookeeper://192.168.1.101:2181?timeout=20000
    8. dubbo.config-center.address=zookeeper://192.168.1.101:2181?timeout=20000
    9. dubbo.metadata-report.address=zookeeper://192.168.1.101:2181?timeout=20000

    服务启动后,相应的dubbo服务信息会保存在zookeeper上

    dubbo + spring

    原始基于spring集成dubbo,不基于dubbo注解

    service api和service api provider和上面类似,只是注册和发现dubbo服务的方式不同,spring基于配置,而springboot基于注解

    applicationContext.xml

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
    5. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    6. <dubbo:application name="coupon-service-provider"/>
    7. <dubbo:registry address="zookeeper://192.168.1.101:2181?timeout=60000"/>
    8. <dubbo:protocol name="dubbo"/>
    9. <dubbo:service interface="org.normal.example.ICouponService" ref="couponService"/>
    10. <bean id="couponService" class="com.normal.coupon.couponserviceprovider.service.CouponService"/>
    11. beans>

    application.properties

    1. # 应用名称
    2. spring.application.name=coupon-service-provider

    Dubbo高级应用

    服务注册与发现

    Apache Dubbo天然就支持服务注册发现,最早开源的时候,官方建议使用 Apache Zookeeper作为注册中心。因此到现在仍然还有很多公司是Dubbo+Zookeeper这样一个架构。

    从Apache Dubbo2.7.x版本开始,支持的注册中心增加了很多,包括: Consul、Etcd、Nacos、Sofa、Zookeeper、Eureka、Redis。

    但是在Dubbo3.x版本里面,默认又只支持Nacos和Zookeeper两种,其他的注册中心被分离出来作为独立的组件,如果需要用到,则需要单独增加这些组件的依赖。可以参考dubbo官网文档扩展点分离:https://dubbo.apache.org/zh/docs/new-in-dubbo3/#%E6%89%A9%E5%B1%95%E7%82%B9%E5%88%86%E7%A6%BB

    1. <properties>
    2. <dubbo.version>3.0.0dubbo.version>
    3. properties>
    4. <dependencies>
    5. <dependency>
    6. <groupId>org.apache.dubbogroupId>
    7. <artifactId>dubboartifactId>
    8. <version>${dubbo.version}version>
    9. dependency>
    10. <dependency>
    11. <groupId>org.apache.dubbogroupId>
    12. <artifactId>dubbo-dependencies-zookeeperartifactId>
    13. <version>${dubbo.version}version>
    14. <type>pomtype>
    15. dependency>
    16. <dependency>
    17. <groupId>org.apache.dubbogroupId>
    18. <artifactId>dubbo-registry-redisartifactId>
    19. <version>${dubbo.version}version>
    20. dependency>
    21. dependencies>

    Dubbo负载均衡

    一致性hash,随机,轮询,最小活跃度,最小响应时间,

    Dubbo容错策略

    1. failover(默认策略):失败后重试,retries=2,配置重试次数
    2. failfast:只调用一次
    3. failsafe:失败后直接忽略
    4. failback:失败自动恢复,异步重试(MQ)
    5. forking:并发调用多个目标服务节点,只要有一个成功就立刻返回,forks=2,配置并发数量
    6. available:调用目前可用的服务实例,只调用一个
    7. mergeable:对多个服务结果聚合
    8. broadcast:广播,探测,任意失败就返回
    9. zone-aware:同区域的调用

    服务降级

    • 主动降级:大促时候,并发量很高得时候,主动把一些非核心功能下架,或者降低服务器数量
    • 被动降级:当某个服务出现问题无法访问时,会进行容错降级处理
      • 异常降级
      • 限流降级
      • 熔断降级

    接口异步调用

    1. @DubboReference(async = true)
    2. IUserService userService;

    调用链路的隐式传参

    可以在api服务中赋值

    RpcContext.getContext().setAttachment("parameter-key", "parameter-value");

    在provider实现中取值

    RpcContext.getContext().getAttachment("parameter-key");

    多协议支持

    dubbo协议,dubbo 3.x提供了Triple协议

    多序列化

    考虑两方面因素:计算效率,序列化之后数据的压缩大小

    对外:JSON

    对内:Dubbo(Hessian2)

    针对Java语言:Kryo, FST

    跨语言:Protobuf, Avro, Jute(zookeeper), 

    不同序列化方式对比

    序列化方式请求字节数响应字节数
    Kryo27290
    FST28896
    Dubbo Serialization430186
    Hessian546329
    FastJson461218
    Json657409
    Java Serialization963630

    泛化调用

  • 相关阅读:
    数据库可视化工具分享 (DBeaver)
    GitHub详细教程
    DS-Net:可落地的动态网络,实际加速1.62倍,快改造起来 | CVPR 2021 Oral
    Autovue集成全过程
    我选择了MySQL和SpringData JPA!
    学Python的漫画漫步进阶 -- 第六步
    使用 FasterTransformer 和 Triton 推理服务器部署 GPT-J 和 T5
    一文了解 Java 中的构造器
    AGENS算法c++实现
    clion 中的undefined reference to 问题解决
  • 原文地址:https://blog.csdn.net/luciferlongxu/article/details/127341723