Solving Data Consistency Problems in a Microservices Architecture

Alibaba Cloud
7 min readApr 24, 2019

Practices for solving data consistency problems in a microservices architecture

With rapid business development, monolithic architectures show many problems, such as low code maintainability, low fault tolerance, difficult testing, and poor agile delivery capabilities. To solve these problems, microservices were born. Although microservices can solve the aforementioned problems, it also brings about new problems, one of which is how to ensure business data consistency between microservices.

This article uses a commodity purchase case to explain how Fescar can ensure business data consistency under the microservices architecture Dubbo. In the example described in this article, the registration, configuration, and service center for both Dubbo and Fescar is Nacos. Fescar later than 0.2.1 supports the Nacos registration, configuration, and service center.

Business Description

The commodity purchase business includes three microservices:

  • Storage service: deducts the inventory quantity of a given item.
  • Order service: generates an order based on a purchase request.
  • Account service: deducts a specific amount from the user account.

The business structure is as follows:


public interface StorageService {    
* deduct storage count
void deduct(String commodityCode, int count);


public interface OrderService {    
* create order
Order create(String userId, String commodityCode, int orderCount);


public interface AccountService {    
* debit balance of user's account
void debit(String userId, int money);

Note: The three preceding microservices are all deployed independently.

Implementing Data Consistency

Step 1: Initialize the MySQL database (The InnoDB storage engine is required)

Modify the connection information for StorageService, OrderService, and AccountService in resources/jdbc. properties.

# storage db config
# order db config

Step 2: Create the undo_log table (for use in the Fescar AT mode) and related business table

Related scripts for creating tables can be found under “resources/sql/”. Run the business table creation script in dubbo_biz.sql in the corresponding database and run the undo_log.sql table creation script in each database.

CREATE TABLE undo_log (

`id` bigint(20) NOT NULL AUTO_INCREMENT,  
`branch_id` bigint(20) NOT NULL,
`xid` varchar(100) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int(11) NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
`ext` varchar(100) DEFAULT NULL,
KEY `idx_unionkey` (`xid`,`branch_id`)
DROP TABLE IF EXISTS `storage_tbl`;
CREATE TABLE `storage_tbl` (
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT 0,
UNIQUE KEY (`commodity_code`)
CREATE TABLE `order_tbl` (
`user_id` varchar(255) DEFAULT NULL,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT 0,
`money` int(11) DEFAULT 0,
DROP TABLE IF EXISTS `account_tbl`;
CREATE TABLE `account_tbl` (
`user_id` varchar(255) DEFAULT NULL,
`money` int(11) DEFAULT 0,

Note: Ensure that each physical database includes the undo_log table. In this example, a physical database can be used to represent the independent logic database of the three preceding microservices.

Step 3: Introduce POM dependencies for Fescar, Dubbo and Nacos



Note: Because apache-dubbo is currently incompatible with dubbo-registry-nacos jar, the apache.dubbo dependency should be excluded from fescar-dubbo and alibaba-dubbo should be manually added. Later apache-dubbo (2.7.1+) will be compatible with dubbo-registry-nacos. In Fescar, fescar-dubbo jar supports apache.dubbo and fescar-dubbo-alibaba jar supports alibaba-dubbo.

Step 4: Configure the Provider Spring for the microservices

Perform the following configuration in the Spring configuration files of the three microservices (dubbo-account-service.xml, dubbo-order-service and dubbo-storage-service.xml):

  • Configure Fescar data source proxy
<bean id="accountDataSourceProxy" class="">
<constructor-arg ref="accountDataSource"/>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="accountDataSourceProxy"/>
</bean> is required to wrap Druid data source as the direct business data source. DataSourceProxy is used for intercepting and resolving business SQL as well as interacting with TC to coordinate transaction operation status.

  • Configure the Dubbo registration center.
<dubbo:registry address="nacos://${nacos-server-ip}:8848"/>
  • Configure Fescar GlobalTransactionScanner.
<bean class="">
<constructor-arg value="dubbo-demo-account-service"/>
<constructor-arg value="my_test_tx_group"/>

The first parameter of the constructor is the custom business applicationId. If multiple microservices are to be deployed on a single machine, the applicationId must be unique.

The second parameter of the constructor is the logical group of the Fescar transaction service. This group uses the “service.vgroup_mapping.my_test_tx_group” configuration item in the configuration center to map to the corresponding Fescar-Server cluster name, and then obtains the list of available services based on the cluster name “.grouplist”.

Step 5: Configure the transaction initiator

Make the following configuration in dubbo-business.xml:

  • Configure the Dubbo registration center.
    Identical to step 4
  • Configure Fescar GlobalTransactionScanner.
    Identical to step 4
  • Add the “@GlobalTransactional” annotation to the service method of the transaction initiator.
@GlobalTransactional(timeoutMills = 300000, name = "dubbo-demo-tx")

“timeoutMills” is the total transaction timeout time (60s by default). “name” is the alias of the transaction method signature (set to null by default). All the parameters in the annotation can be omitted.

Step 6: Start Nacos-Server

  • Download and decompress the latest Nacos-Server release package.
  • Run Nacos-server.


sh -m standalone


cmd startup.cmd -m standalone

Access the Nacos console: http://localhost:8848/nacos/index.html?spm=a2c41.12785185.0.0.40d350b9AuwySE#/configurationManagement?dataId=&group=&appName=&namespace

If it’s able to be accessed, the Nacos-Server service is running successfully (default account/password: nacos/nacos).

Step 7: Start Fescar-Server

  • Download and decompress the latest Fescar-Server release package.
  • Initialize the Fescar configuration.

Go to the conf folder under the directory where Fescar-Server is decompressed, confirm the configuration value for the nacos-config.txt (generally modification is not required) and then run the script to initialize the configuration.

sh $Nacos-Server-IP


sh localhost

The final output of this script is “init nacos config finished, please start fescar-server.” This indicates that the push configuration was successful. If you want to further check the configuration, log on to the Nacos console, go to the configuration list and filter the configuration item with Group=FESCAR_GROUP.

  • Change the Fescar-server service registration method to nacos.

Find registry.conf in the conf folder under the directory where Fescar-Server is decompressed, change the type to nacos and configure the related properties of Nacos.

registry {  
# file nacos
type = "nacos"
nacos {
serverAddr = "localhost"
namespace = "public"
cluster = "default"
file {
name = "file.conf"

type: It can be configured as nacos and file. When configured as file, service registration is unavailable.

nacos.serverAddr: Nacos-Sever service address (the port number is excluded)

nacos.namespace: the independent namespace for Nacos registration and configuration

nacos.cluster: the cluster name of the registration service the name of the configuration file under classpath when type is set to file

  • Run Fescar-server


sh $LISTEN_PORT $PATH_FOR_PERSISTENT_DATA $IP (This parameter is optional)


cmd fescar-server.bat $LISTEN_PORT $PATH_FOR_PERSISTENT_DATA $IP (This parameter is optional)

LISTENPORT: the service port of Fescar-Server

PATH_FOR_PERSISTENT_DATA: Path of the transaction operation record file (the path already exists)

$IP (optional): the IP used for specify the registration service of Fescar-Server in a multi-IP environment

eg: sh 8091 /home/admin/fescar/data/

After running the server, you can see that the service name in the Nacos console is serverAddr:

Step 8: Start and test the microservices

  • Change the registration discovery method of the business client to nacos.

Similar to the [Change the Fescar-server service registration method to nacos] section in Step 7

  • Start DubboAccountServiceStarter.
  • Start DubboOrderServiceStarter.
  • Start DubboStorageServiceStarter.

After the startup, in the Nacos console, you can see three providers in the service list:

  • Start DubboBusinessTester for testing.

Note: Only exceptions thrown in the methods with the @GlobalTransactional annotation will trigger transaction rollback. The entire Dubbo service call link only needs to annotate the service method of the original transaction initiator.

The eight preceding steps allow us to ensure data consistency among the three independent microservices in the commodity purchase business: storage, order, and account.

Reference links:

Sample in this article:




About the Author

Qing Ming is one of the initiators of the Open Source Fescar project and one of the core members of the Alibaba middleware TXC/GTS R&D team. The author has been engaged in the core R&D work of distributed middleware for a long time and is very experienced in the distributed transaction field.




Alibaba Cloud

Follow me to keep abreast with the latest technology news, industry insights, and developer trends. Alibaba Cloud website: