公司Dubbo项目Service Mesh改造

前言

    公司的分布式架构是基于Alibaba Dubbo实现的,微服务的相关治理也是基于Alibaba Dubbo做的,随着公司系统规模的增长服务发布服务的治理注册中心的压力硬件成本等问题逐渐的凸显出来,尤其是服务发布服务治理,比如多版本的发布,金丝雀发布,精细化的流量控制等,用Alibaba Dubbo实现这些分布式语义很麻烦,在Service Mesh架构下,解决这些问题都会变得容易,基于此,本篇介绍一下公司Dubbo项目Service Mesh改造方案。

其他基础架构

    除了Alibaba Dubbo,公司使用Zookeeper作为配置中心,分布式消息队列rocketmq,分布式缓存redis,阿里云分库分表产品DRDS,阿里云关系型数据库RDS,这些基础组件在整个Service Mesh架构的改造中是不变的。

Dubbo项目Service Mesh改造具体实现

基础技术方案

    将Dubbo架构改造成Service Mesh架构就要Dubbo框架从项目中移除,我们这里将Dubbo框架移除,并且将服务端接口全部改造成rest接口,这就需要服务端使用新的容器发布rest接口,所以干脆就将项目改造成Sping Boot Web应用,协议问题没有了,但是如何尽可能改动小的能够让消费端快速的接入Sping Boot Web应用的服务端就成为了难点,由于Dubbo项目API模块的作用与Spring Cloud Feign模块的作用十分相似,模块内都是一些interface,需要服务端定义xxxServiceImpl去实现各个interface,然后消费者通过Spring依赖注入将interface注入并使用,这就使得Dubbo最复杂的服务间调用方式有了解决的方案。

基础组件改造

  • 根pom.xml引入SpringBoot parent,增加 spring-cloud-dependencies import引用
  • 删除所有dubbo相关引用。

这一步骤简单来说就是将pom.xml中Dubbo的所有jar依赖全部删除,并且引入SpringBoot parent和 spring-cloud-dependencies的引用,例如:

改造前:


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>

    <dependencies>
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>dubboartifactId>
            <version>2.8.4version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-log4j12artifactId>
                    <groupId>org.slf4jgroupId>
                exclusion>
                <exclusion>
                    <artifactId>log4jartifactId>
                    <groupId>log4jgroupId>
                exclusion>
                <exclusion>
                    <groupId>org.apache.curatorgroupId>
                    <artifactId>curator-clientartifactId>
                exclusion>
                <exclusion>
                    <artifactId>curator-frameworkartifactId>
                    <groupId>org.apache.curatorgroupId>
                exclusion>
            exclusions>
        dependency>
        <dependency>
            <groupId>com.github.sgroschupfgroupId>
            <artifactId>zkclientartifactId>
            <version>0.1version>
            <exclusions>
                <exclusion>
                    <artifactId>zookeeperartifactId>
                    <groupId>org.apache.zookeepergroupId>
                exclusion>
            exclusions>
        dependency>
        <dependency>
            <groupId>org.apache.zookeepergroupId>
            <artifactId>zookeeperartifactId>
            <version>3.4.6version>
            
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-log4j12artifactId>
                    <groupId>org.slf4jgroupId>
                exclusion>
                <exclusion>
                    <artifactId>log4jartifactId>
                    <groupId>log4jgroupId>
                exclusion>
            exclusions>
        dependency>
    dependencies>
project>

改造后:


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-openfeignartifactId>
            <version>2.2.3.RELEASEversion>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-apiartifactId>
                    <groupId>org.slf4jgroupId>
                exclusion>
                <exclusion>
                    <artifactId>feign-hystrixartifactId>
                    <groupId>io.github.openfeigngroupId>
                exclusion>
                <exclusion>
                    <artifactId>spring-cloud-starter-netflix-ribbonartifactId>
                    <groupId>org.springframework.cloudgroupId>
                exclusion>
                <exclusion>
                    <artifactId>spring-cloud-starter-netflix-archaiusartifactId>
                    <groupId>org.springframework.cloudgroupId>
                exclusion>
                <exclusion>
                    <artifactId>spring-cloud-netflix-ribbonartifactId>
                    <groupId>org.springframework.cloudgroupId>
                exclusion>
            exclusions>
        dependency>
    dependencies>
project>

Dubbo门面API改造

  1. pom.xml增加spring-cloud-starter-openfeign引用。

  2. 删除所有Dubbo相关引用Dubbo相关配置文件。

  3. Dubbo原有API接口是标准的JAVA接口定义,与Feign Restful接口定义十分类似。这里可以在原有的API接口基础上增加 @FeignClient@RequestMapping等注解,将一个普通的API接口改造成一个Feign Restful接口,后续会使用Feign这个 Restful框架来处理服务间调用等问题。由于Feign本身是自带了Ribbon负载均衡,服务访问者经过负载均衡后会找到服务提供者的一个 IP+Port进行调用,这与K8S Service要求的服务名调用的方式相冲突,所以必须想办法去掉Feign自带的负载均衡。好在 @FeignClient可以手工指定一个固定的调用地址,这里可以把这个地址设置成K8S Servicename名称,从而实现了通过FeignK8S Service服务名调用的能力。此部分需要每个API接口增加注解一次,改造工作量相对可控。

  4. 由于Feign要求接口使用Restful格式,所以接口中的每个抽象方法都必须添加@RequestMapping,@GetMapping,@PostMapping等注解暴露成一个Restful资源地址。此部分改造涉及到每个API接口的每个抽象方法,是整个方案里改动量最大的一部分。

  5. 此部分整体改造工作量取决于原有的Dubbo项目包含多少个API接口,以及每个API包含多少个抽象方法。

改造前示例:

public interface IOdaApi {

    ModelsReturn<ModelsCommonResponse<ConsumptionODAResponse>> consumptionODA(ConsumptionODARequest consumptionODARequest);

    ModelsReturn<ModelsCommonResponse<RefundODAResponse>> refundODA(RefundODARequest refundODARequest);

    ModelsReturn<ModelsCommonResponse<ConsumptionODAResponse>> consumptionQueryODA( ConsumptionQueryODARequest consumptionQueryODARequest);

    ModelsReturn<ModelsCommonResponse<String>> repayODA(RepayODARequest repayODARequest);
}

改造后示例:

@FeignClient(name = "miss-xxx-svc", url = "http://miss-xxx-svc:8080")
public interface IOdaApi {

    @PostMapping(value = "/xxxService/consumptionODA")
    ModelsReturn<ModelsCommonResponse<ConsumptionODAResponse>> consumptionODA(@RequestBody ConsumptionODARequest consumptionODARequest);
}

Dubbo Provider端改造

  1. pom.xml增加spring-boot-starter-webspring-cloud-starter-openfeign等引用,同时增加SpringBoot mainClass 标准启动项配置。删除所有Dubbo相关引用、Dubbo相关配置文件。

  2. 增加SpringBoot启动类,增加@SpringBootApplication@EnableFeignClients两个注解,配置dubbo provider服务端口号。

  3. xxxServiceImpl服务实现类上增加@RestController注解,提供 consumer Restful 访问的能力。 这个需要每个服务实现类都加上@RestController注解,不要遗漏。

  4. 此部分大都属于一次性改动,改造工作量相对可控。

改造后示例:

pom


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>

    <parent>
        ...
    parent>

    <artifactId>MISS.xxxServiceartifactId>

    <dependencies>
        <dependency>
            <groupId>com.xxx.xxxgroupId>
            <artifactId>MISS.xxxService.APIartifactId>
            <version>2.0.5-RELEASEversion>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-openfeignartifactId>
        dependency>
    dependencies>

    <build>
        ...
    build>
project>

改造后的 OdaImpl.java 代码示例(改造前只是缺少 @RestController 注解,其他代码完全一致):

@Slf4j
@RestController
public class OdaImpl implements IOdaApi {

    @Resource
    private OdaService odaService;

    @Override
    public ModelsReturn<ModelsCommonResponse<ConsumptionODAResponse>> consumptionODA(ConsumptionODARequest consumptionODARequest) {
        try {
            Validation.validate(consumptionODARequest);

            ...

            return ErrorCode.returnMsg(ErrorCode.OPSERATE_SUCCESS, odaService.consumptionODA(consumptionODARequest.getMultiIndustryInfo(),consumptionODA));

        } catch (Exception e) {
            log.error(LogUtil.exceptionMarker(), "ODA交易异常",e);
            return ErrorCode.returnMsgByErrorMessage(ErrorCode.PARA_ERROR, "ODA交易异常");
        }
    }
}

Dubbo Comsumer端改造

  1. pom.xml增加spring-boot-starter-webspring-cloud-starter-openfeign等引用,同时增加SpringBoot mainClass 标准启动项配置。

  2. 删除所有Dubbo相关引用、Dubbo相关配置文件。

  3. 增加SpringBoot启动类,增加@SpringBootApplication@EnableFeignClients(需要配置 basePackages 扫描包路径) 两个注解,并配置dubbo consumer服务端口号。

  4. 此部分大都属于一次性改动,改造工作量相对可控。

由于dubbo consumer项目改造与dubbo provider改造极其相似,这里不再贴出代码示例。

总结

    至此Dubbo项目的Service Mesh改造就已经完成了,k8s + Istio的部署这里就不做介绍了,此方案是在我司成功落地的技术方案,并且使用次方案进行改造的服务也具有一定规模,目前生产环境还没有遇到任何问题。

    此种改造方案改动量相对于完全的去掉dubbo而不使用feign改造的方式来说改动较小,如有更好的改造方案欢迎交流。

你可能感兴趣的:(架构,java,开发语言,service_mesh,分布式)