Demo应用接入Msha SDK示例

更新时间:2025-03-13 02:12:49
重要

本文中含有需要您注意的重要提示信息,忽略该信息可能对您的业务造成影响,请务必仔细阅读。

本文以异地应用双活架构为例,采用Msha SDK 1.5.7-SNAPSHOT版本,接入Redis、MySQL两个类型的数据库,文中提供了Spring Cloud版本的Demo供参考。更多MSHA SDK接入信息参考:同城多活MshaSDK使用手册异地应用双活MshaSDK使用手册

一、前提条件

  • 准备环境:JDK8、Maven3

  • 准备数据库:MySQL 5.7/8、Redis 6.0

  • 准备中间件:MSE的注册中心,或者自己搭建EurekaNacos。

    • 自建Eureka版本需要与Demo对应。

二、Demo示例工程

  1. MSHA提供了基于Maven的示例工程。您可以在本地设备上编译和运行示例工程,也可以以示例工程为基础开发您的应用。

    1. Maven示例工程:ahas-demo-open_msha_sdk-demo_20250307.zip

    2. 项目中添加依赖包

      <dependency>
         <groupId>com.aliyun.msha</groupId>
         <artifactId>msha-router-all</artifactId>
         <version>${msha-sdk.version}</version>
      </dependency>
说明
  • 项目中依赖的MshaSDK包,可在MSHA控制台下载(位置:MSHA控制台 > 多活实例 > 多活实例列表进入多活实例 > SDK下载菜单栏)

    • msha-router-all

  • 项目中需要手动在MySQL中创建好数据库,应用启动时会自动创建表。

三、Demo功能模块介绍及改造

1. frontend服务

1.1. 介绍

  1. 电商平台,提供视图和控制器服务。

1.2. 改造点

  1. 本云Eureka连接地址。(文件路径:frontend/src/main/resources/application.properties)

    eureka.client.serviceUrl.defaultZone=http://username:password@eureka:8761/eureka/
  2. MQ需要可以配置,不需要可以注释掉,不影响服务运行。

2. cart服务

2.1. 介绍

  1. 电商平台,提供购物车功能,数据存储在Redis中。

2.2. 改造点

  1. 项目pom.xml中添加Redis Jedis SDK。(文件路径:cartservice/cartservice-provider/pom.xml)

    <dependency>
      <groupId>com.aliyun.unit.router</groupId>
      <artifactId>msha-bridge-redis-jedis</artifactId>
      <version>${msha-sdk.version}</version>
    </dependency>
  2. 本云Eureka连接地址。(文件路径:cartservice/cartservice-provider/src/main/resources/application.properties)

    eureka.client.serviceUrl.defaultZone=http://username:password@eureka:8761/eureka/
  3. Redis连接地址,primary为主库地址,standby为备库地址。(文件路径:cartservice/cartservice-provider/src/main/resources/application.properties)

    spring.redis.host.primary=${REDIS_CENTER:NO_REDIS_ENV}
    spring.redis.host.standby=${REDIS_STANDBY:NO_REDIS_ENV}
    spring.redis.port=6379
    spring.redis.password=${password}
  4. 添加Redis配置类(文件路径:cartservice/cartservice-provider/src/main/java/com/alibabacloud/hipstershop/cartserviceprovider/config/RedisConfig.java)

    package com.alibabacloud.hipstershop.cartserviceprovider.config;
    
    import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;
    import com.aliyun.msha.bridge.redis.jedis.jedis.pool.MshaJedisPool;
    import com.aliyun.msha.bridge.redis.jedis.spring.MshaJedisConnectionFactory;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.util.Pool;
    
    import java.lang.reflect.Field;
    
    /**
     * @author yanshan.sy
     * @date 2024/02/13
     */
    @Configuration
    public class RedisConfig {
    
        @Value("${spring.redis.host.primary}")
        private String primaryHost;
    
        @Value("${spring.redis.host.standby}")
        private String standbyHost;
    
        @Value("${spring.redis.password}")
        private String password;
    
        @Value("${spring.redis.port}")
        private int port;
    
        @Bean
        JedisConnectionFactory jedisConnectionFactory() throws NoSuchFieldException, IllegalAccessException {
    
            Pool<Jedis> pool = new MshaJedisPool(primaryHost, port, password, standbyHost, port, password, 0);
            JedisConnectionFactory jedisConnectionFactory = new MshaJedisConnectionFactory(pool);
            Class<JedisConnectionFactory> clazz = JedisConnectionFactory.class;
            Field poolField = clazz.getDeclaredField("pool");
            poolField.setAccessible(true);
            poolField.set(jedisConnectionFactory, pool);
            return jedisConnectionFactory;
        }
    
        @Bean
        public RedisTemplate<String, Object> redisTemplate(JedisConnectionFactory jedisConnectionFactory) {
            RedisTemplate<String, Object> template = new RedisTemplate<>();
            template.setConnectionFactory(jedisConnectionFactory);
            template.setDefaultSerializer(new FastJsonRedisSerializer<>(Object.class));
            return template;
        }
    
    }
    

3. checkout服务

3.1. 介绍

  1. 电商平台,提供订单信息服务,数据存储MySQL数据库中。

3.2. 改造点(文件路径:checkoutservice/checkoutservice-provider/src/main/resources/application.properties)

  1. 本云Eureka连接地址。

    eureka.client.serviceUrl.defaultZone=http://username:password@eureka:8761/eureka/
  2. MySQL连接地址

    1. 应用在spring properties文件中配置数据库连接参数,则需要在该文件进行修改。默认数据库连接地址是主云数据库地址,而在URL参数中增加另外一朵云(备云)的数据库连接地址(即备库)。

      spring.datasource.url=jdbc:mysql://${主云的数据库连接地址}:3306/xxxDbName?useUnicode=true&characterEncoding=UTF-8&mshaStandbyHost=${备云的数据库连接地址}&mshaStandbyPort=3306
      spring.datasource.username=username
      spring.datasource.password=password
    2. 应用在spring properties文件中配置JDBC Driver,则需要将原生的 com.mysql.jdbc.Driver 替换为MSHA SDK中提供Drivercom.ali.unit.router.driver.Driver。

      spring.datasource.driver-class-name=com.ali.unit.router.driver.Driver

4. product服务

4.1. 介绍

  1. 电商平台,提供产品信息服务,数据存储MySQL数据库中。

4.2. 改造点(文件路径:productservice/productservice-provider/src/main/resources/application.properties)

  1. 本云Eureka连接地址。

    eureka.client.serviceUrl.defaultZone=http://username:password@eureka:8761/eureka/
  2. MySQL连接地址

    1. 应用在spring properties文件中配置数据库连接参数,则需要在该文件进行修改。默认数据库连接地址是主云数据库地址,而在URL参数中增加另外一朵云(备云)的数据库连接地址(即备库)。

      spring.datasource.url=jdbc:mysql://${主云的数据库连接地址}:3306/xxxDbName?useUnicode=true&characterEncoding=UTF-8&mshaStandbyHost=${备云的数据库连接地址}&mshaStandbyPort=3306
      spring.datasource.username=username
      spring.datasource.password=password
    2. 应用在spring properties文件中配置JDBC Driver,则需要将原生的 com.mysql.jdbc.Driver 替换为MSHA SDK中提供Drivercom.ali.unit.router.driver.Driver。

      spring.datasource.driver-class-name=com.ali.unit.router.driver.Driver

5. trace服务

5.1. 介绍

  1. 电商平台,提供追踪信息服务,数据存储MySQL数据库中。

5.2. 改造点(文件路径:traceservice/src/main/resources/application.properties)

  1. 本云Eureka连接地址。

    eureka.client.serviceUrl.defaultZone=http://username:password@eureka:8761/eureka/
  2. MySQL连接地址

    1. 应用在spring properties文件中配置数据库连接参数,则需要在该文件进行修改。默认数据库连接地址是主云数据库地址,而在URL参数中增加另外一朵云(备云)的数据库连接地址(即备库)。

      spring.datasource.url=jdbc:mysql://${主云的数据库连接地址}:3306/xxxDbName?useUnicode=true&characterEncoding=UTF-8&mshaStandbyHost=${备云的数据库连接地址}&mshaStandbyPort=3306
      spring.datasource.username=username
      spring.datasource.password=password
    2. 应用在spring properties文件中配置JDBC Driver,则需要将原生的 com.mysql.jdbc.Driver 替换为MSHA SDK中提供Drivercom.ali.unit.router.driver.Driver。

      spring.datasource.driver-class-name=com.ali.unit.router.driver.Driver

四、Demo运行说明

  1. 运行时需要添加环境变量

    -Dregion-id=${实际的地域ID}
    -Dzone-id=${实际的可用区ID}
    -Downer-account-id=${实际的阿里云主账号ID}
    -Dmsha.app.name=${应用名称}
    -Dmsha.namespaces=${多活命名空间ID}
    -Dmsha.nacos.namespace=${DNCS/ACM 命名空间ID}
    -Dmsha.nacos.server.addr=${DNCS/ACM 连接地址}
    • ${实际的地域ID},混合云场景(含自建IDC或非阿里云场景)需要填写,不填写的话 MSHA 根据 阿里云ECS元数据接口获取机器所属地域。

    • ${实际的可用区ID},混合云场景(含自建IDC或非阿里云场景)需要填写,不填写的话 MSHA 根据 阿里云 ECS 元数据接口获取机器所属可用区。

    • ${应用名称},为您实际的应用名,应用名称不支持中文。

    • ${多活命名空间ID},可以登录MSHA管控平台,菜单栏选择多活实例 > 多活列表页面,列表查看已经创建好的多活命名空间ID。

    • msha.nacos.namespacemsha.nacos.server.addrNacos的命名空间ID和连接地址。

    • 添加spring.profiles.active变量使对应环境的配置生效。

      1. 例:-Dspring.profiles.active=cn-hangzhou

说明
  1. 下载代码包,无需修改直接使用Maven编译打包,然后执行如下运行命令。

    1. 运行命令参考(注意,包含特殊字符,如&、?等,需要用引号将参数括起来)

nohup java -Dspring.profiles.active=cn-hangzhou -Dregion-id=${云regionID} -Dzone-id=${云可用区ID} -Downer-account-id=${云owner账号ID} -Dmsha.namespaces=${MSHA多活实例ID} -Dmsha.nacos.namespace=${nacos命名空间ID} -Dmsha.nacos.server.addr=${nacos连接地址} -Dmsha.app.name=productservice -jar /*/*/productservice.jar --eureka.client.serviceUrl.defaultZone="http://${username}:${password}@${eurekaURL}:8761/eureka/" --spring.datasource.username=${username} --spring.datasource.password=${password} --spring.datasource.url="jdbc:mysql://${主云的数据库连接地址}:3306/product?characterEncoding=utf8&useSSL=false&serverTimezone=GMT&mshaStandbyHost=${备云的数据库连接地址}&mshaStandbyPort=3306" -> /*/*/productservice.log 2>&1 &
警告

如果选择EDAS部署应用,在部署时,配置中心在MSE申请并绑定到了EDAS的配置中心,那么环境变量msha.nacos.*需要填写EDAS的配置中心中分配的命名空间ID连接地址(EndPoint)。 MSHA控制台创建多活实例时选择【管控命令通道配置】也需要填写EDAS中分配的命名空间ID连接地址(EndPoint)。

  1. 运行成功后浏览器请求http://IP:8080访问电商平台主页。

五、接入MSHA控制台

1. 创建多活实例

  1. 异地应用双活实例新建实例

2. 数据层配置

  1. 异地应用双活实例配置数据层,参考数据源(MySQL、Redis)录入和保护规则录入部分,数据同步链路可先不录入。

3. 主备切换测试

  1. 访问电商平台主页,确定访问的是主云数据库数据。(可以在数据库中写入标识数据)

  2. 操作主备切换异地应用双活切流,参考故障 > 数据库故障部分。

    重要
    • 没有创建数据同步链路时会报警告,测试项目,为了提高效率此处点击跳过

  3. 主备切换完成,访问电商平台主页,确定访问的是切换后的主云(原备云)数据库数据。

  4. 测试完成后主备数据库切回。

六、问题

  1. 主备切换数据库不起作用

    1. 检查多活实例是否推送成功,MSHA控制台多活实例 > 实例列表 > 操作-生效详情推送是否成功。

    2. 检查服务运行环境变量Nacos命名空间ID连接地址是否与MSHA控制台多活实例配置的相同。

    3. 检查多活实例连接的Nacos配置中心里是否存在数据库配置。

    4. 检查应用服务器,路径/home/admin/nacos/config/**/snapshot-tenant/**/MSHA_GROUP/下是否有数据库文件信息。

  2. 更多问题参考:常见问题

  • 本页导读 (1)
  • 一、前提条件
  • 二、Demo示例工程
  • 三、Demo功能模块介绍及改造
  • 1. frontend服务
  • 2. cart服务
  • 3. checkout服务
  • 4. product服务
  • 5. trace服务
  • 四、Demo运行说明
  • 五、接入MSHA控制台
  • 1. 创建多活实例
  • 2. 数据层配置
  • 3. 主备切换测试
  • 六、问题