This topic provides a Spring Cloud-based demo application that uses a cross-region active-active architecture. The demo uses Msha SDK version 1.5.7-SNAPSHOT to connect to Redis and MySQL databases. For more information about connecting with the MSHA SDK, see Active Zone-Redundancy MshaSDK User Guide and Cross-region Active-Active Application MshaSDK User Guide.
1. Prerequisites
Required environment: JDK 8 and Maven 3
Required databases: MySQL 5.7 or 8, and Redis 6.0
Required middleware: An MSE registry center, or a self-managed Eureka or Nacos instance.
The version of your self-managed Eureka must match the demo.
2. Demo sample project
MSHA provides a Maven-based sample project. You can compile and run the sample project on an on-premises device or use it as a foundation to develop your application.
Maven sample project: ahas-demo-open_msha_sdk-demo_20250307.zip
Add the dependency package to the project.
<dependency> <groupId>com.aliyun.msha</groupId> <artifactId>msha-router-all</artifactId> <version>${msha-sdk.version}</version> </dependency>
You can download the MshaSDK package that your project depends on from the MSHA console at in the menu bar.
msha-router-all
You must manually create a database in MySQL for the project. The application automatically creates the required tables when it starts.
3. Demo modules: Introduction and modification
1. frontend service
1.1. Introduction
An E-commerce platform service that provides view and controller functionalities.
1.2. Modifications
The Eureka endpoint for the local cloud. (File path: frontend/src/main/resources/application.properties)
eureka.client.serviceUrl.defaultZone=http://username:password@eureka:8761/eureka/Configure the message queue (MQ) as needed. If you do not require MQ, you can comment it out. This does not affect how the service runs.
2. cart service
2.1. Introduction
An E-commerce platform service that provides a shopping cart feature. Data is stored in Redis.
2.2. Modifications
Add the Redis Jedis SDK to the project's pom.xml file. (File path: cartservice/cartservice-provider/pom.xml)
<dependency> <groupId>com.aliyun.unit.router</groupId> <artifactId>msha-bridge-redis-jedis</artifactId> <version>${msha-sdk.version}</version> </dependency>The Eureka endpoint for the local cloud. (File path: cartservice/cartservice-provider/src/main/resources/application.properties)
eureka.client.serviceUrl.defaultZone=http://username:password@eureka:8761/eureka/The Redis endpoint. `primary` is the primary database endpoint, and `standby` is the secondary database endpoint. (File path: 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}Add the Redis configuration class. (File path: 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 service
3.1. Introduction
An E-commerce platform service that provides order information. Data is stored in a MySQL database.
3.2. Modifications (File path: checkoutservice/checkoutservice-provider/src/main/resources/application.properties)
The Eureka endpoint for the local cloud.
eureka.client.serviceUrl.defaultZone=http://username:password@eureka:8761/eureka/MySQL endpoint
If your application configures database connection parameters in the `spring.properties` file, you must modify the file. The default database endpoint is for the primary database. Add the endpoint for the secondary database as a URL parameter.
spring.datasource.url=jdbc:mysql://${primary_cloud_database_endpoint}:3306/xxxDbName?useUnicode=true&characterEncoding=UTF-8&mshaStandbyHost=${secondary_cloud_database_endpoint}&mshaStandbyPort=3306 spring.datasource.username=username spring.datasource.password=passwordIf your application configures the Java Database Connectivity (JDBC) driver in the `spring.properties` file, replace the native `com.mysql.jdbc.Driver` with the `com.ali.unit.router.driver.Driver` class provided by the Msha SDK.
spring.datasource.driver-class-name=com.ali.unit.router.driver.Driver
4. product service
4.1. Introduction
An E-commerce platform service that provides product information. Data is stored in a MySQL database.
4.2. Modifications (File path: productservice/productservice-provider/src/main/resources/application.properties)
The Eureka endpoint for the local cloud.
eureka.client.serviceUrl.defaultZone=http://username:password@eureka:8761/eureka/MySQL endpoint
If your application configures database connection parameters in the `spring.properties` file, you must modify the file. The default database endpoint is for the primary database. Add the endpoint for the secondary database as a URL parameter.
spring.datasource.url=jdbc:mysql://${primary_cloud_database_endpoint}:3306/xxxDbName?useUnicode=true&characterEncoding=UTF-8&mshaStandbyHost=${secondary_cloud_database_endpoint}&mshaStandbyPort=3306 spring.datasource.username=username spring.datasource.password=passwordIf your application configures the JDBC driver in the `spring.properties` file, replace the native `com.mysql.jdbc.Driver` with the `com.ali.unit.router.driver.Driver` class provided by the Msha SDK.
spring.datasource.driver-class-name=com.ali.unit.router.driver.Driver
5. trace service
5.1. Introduction
An E-commerce platform service that provides tracking information. Data is stored in a MySQL database.
5.2. Modifications (File path: traceservice/src/main/resources/application.properties)
The Eureka endpoint for the local cloud.
eureka.client.serviceUrl.defaultZone=http://username:password@eureka:8761/eureka/MySQL endpoint
If your application configures database connection parameters in the `spring.properties` file, you must modify the file. The default database endpoint is for the primary database. Add the endpoint for the secondary database as a URL parameter.
spring.datasource.url=jdbc:mysql://${primary_cloud_database_endpoint}:3306/xxxDbName?useUnicode=true&characterEncoding=UTF-8&mshaStandbyHost=${secondary_cloud_database_endpoint}&mshaStandbyPort=3306 spring.datasource.username=username spring.datasource.password=passwordIf your application configures the JDBC driver in the `spring.properties` file, replace the native `com.mysql.jdbc.Driver` with the `com.ali.unit.router.driver.Driver` class provided by the Msha SDK.
spring.datasource.driver-class-name=com.ali.unit.router.driver.Driver
4. Run the demo
Add the following environment variables at runtime.
-Dregion-id=${your_region_id} -Dzone-id=${your_zone_id} -Downer-account-id=${your_alibaba_cloud_account_id} -Dmsha.app.name=${application_name} -Dmsha.namespaces=${multi_active_namespace_id} -Dmsha.nacos.namespace=${DNCS/ACM_namespace_id} -Dmsha.nacos.server.addr=${DNCS/ACM_endpoint}`${your_region_id}` is required for hybrid cloud scenarios, such as self-managed IDCs or non-Alibaba Cloud environments. If you do not specify this variable, MSHA retrieves the region from the Alibaba Cloud ECS metadata API.
`${your_zone_id}` is required for hybrid cloud scenarios, such as self-managed IDCs or non-Alibaba Cloud environments. If you do not specify this variable, MSHA retrieves the zone from the Alibaba Cloud ECS metadata API.
`${application_name}` is your application name. The application name cannot contain Chinese characters.
To find `${multi_active_namespace_id}`, log on to the MSHA console. On the page, find the ID of your multi-active namespace.
`msha.nacos.namespace` and `msha.nacos.server.addr` are the namespace ID and endpoint of Nacos.
Add the `spring.profiles.active` variable to apply the configuration for the corresponding environment.
Example: `-Dspring.profiles.active=cn-hangzhou`
Download the code package. Then, compile and package it with Maven without modification and run the following command.
Example run command. Note: Enclose parameters in quotation marks if they contain special characters, such as `&` or `?`.
nohup java -Dspring.profiles.active=cn-hangzhou -Dregion-id=${cloud_region_id} -Dzone-id=${cloud_zone_id} -Downer-account-id=${cloud_owner_account_id} -Dmsha.namespaces=${msha_multi_active_instance_id} -Dmsha.nacos.namespace=${nacos_namespace_id} -Dmsha.nacos.server.addr=${nacos_endpoint} -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://${primary_cloud_database_endpoint}:3306/product?characterEncoding=utf8&useSSL=false&serverTimezone=GMT&mshaStandbyHost=${secondary_cloud_database_endpoint}&mshaStandbyPort=3306" -> /*/*/productservice.log 2>&1 &If you deploy the application in Enterprise Distributed Application Service (EDAS) and use the EDAS configuration center, set the `msha.nacos.*` environment variables to the Namespace ID and Endpoint provided by the EDAS configuration center. When you create a in the MSHA console, you must also enter the same Namespace ID and Endpoint for the Control Command Channel Configuration.
After the application starts successfully, open a browser and navigate to `http://<IP_address>:8080` to access the E-commerce platform homepage.
5. Connect to the MSHA console
1. Create a multi-active instance
To create a geo-redundant active-active application instance, see Create an instance.
2. Configure the data layer
For a geo-redundant active-active application instance, configure the data layer. Follow the instructions in the sections about data source (MySQL and Redis) entry and protection rule entry. You do not need to configure the Data Synchronization Link at this stage.
3. Test the primary/secondary switch
Access the E-commerce platform homepage. Confirm that you are accessing data from the primary database. You can write an identifier to the database to verify this.
Perform a primary/standby switchover. For instructions, see Geo-redundant active-active application traffic switching, specifically the section.
ImportantA warning appears if you have not created a Data Synchronization Channel. For this test project, click Skip to proceed.
After the primary/secondary switch is complete, access the E-commerce platform homepage. Confirm that you are accessing data from the new primary database, which was the original secondary database.
After the test is complete, switch the primary and secondary databases back to their original roles.
Troubleshooting
The primary/secondary database switch does not work
Check whether the multi-active instance was pushed successfully in the MSHA console. You can find this information on the page.
Check whether the Nacos Namespace ID and Endpoint in the service's runtime environment variables are the same as those configured for the Multi-active Instance in the MSHA console.
Check whether the database configuration exists in the Nacos configuration center that is connected to the Multi-active Instance.
On the application server, check whether the database file information exists in the `/home/admin/nacos/config/**/snapshot-tenant/**/MSHA_GROUP/` path.
For more information, see FAQ.