This is an automated email from the ASF dual-hosted git repository.
zhanglei pushed a commit to branch zhanglei-path-1
in repository https://gitbox.apache.org/repos/asf/servicecomb-website.git
The following commit(s) were added to refs/heads/zhanglei-path-1 by this push:
new 41abd9f Update package name error in the document
41abd9f is described below
commit 41abd9f85b59e3a264736ea02e10ab2b9ebbff71
Author: Lei Zhang <[email protected]>
AuthorDate: Mon Oct 21 21:16:13 2019 +0800
Update package name error in the document
---
_docs/cn/quick-start-dataconsistency.md | 920 ++++++++++++++--------------
_docs/quick-start-dataconsistency.md | 924 ++++++++++++++---------------
_posts/cn/2018-04-04-saga-pack-design.md | 4 +-
_posts/cn/2018-04-28-saga_with_cucumber.md | 4 +-
4 files changed, 926 insertions(+), 926 deletions(-)
diff --git a/_docs/cn/quick-start-dataconsistency.md
b/_docs/cn/quick-start-dataconsistency.md
index 8eca802..1f0e105 100755
--- a/_docs/cn/quick-start-dataconsistency.md
+++ b/_docs/cn/quick-start-dataconsistency.md
@@ -1,460 +1,460 @@
----
-title: "数据一致性解决方案"
-lang: cn
-ref: quick-start-dataconsistency
-permalink: /cn/docs/quick-start-dataconsistency/
-excerpt: "介绍ServiceComb的Saga数据一致性方案应用demo"
-last_modified_at: 2017-09-19T11:50:10-04:00
----
-
-{% include toc %}
-模拟一个简单的旅行应用,展示如何使用ServiceComb提供的Saga方案保证微服务间数据一致性。
-
-旅行应用包含四个微服务:
-- 机票预订服务(flight-booking-service)
-- 租车服务(car-rental-service)
-- 酒店预订服务(hotel-reservation-service)
-- 支付服务(payment-service)
-
-机票预订、租车、酒店预订服务间无依赖关系,使用自己的数据库,通过HTTP协议通信。
-在以上三个服务的预订成功,支付完成后才能满足一个成功的行程,否则不能成行,Saga自动补偿。
-
-
-
-## 运行demo
-
-注:Demo 集成在 [ServiceComb-Saga](https://github.com/apache/servicecomb-saga) 项目中。
-
-1. 准备环境
-- [Oracle JDK
1.8](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
-- [Maven 3.x](https://maven.apache.org/install.html)
-- [Docker](https://www.docker.com/get-docker)
-- [MySQL](https://dev.mysql.com/downloads/)
-- [Service Center](https://github.com/apache/servicecomb-service-center)
-- [Docker compose](https://docs.docker.com/compose/install/)
-
-2. 配置服务
- 在各服务的 *microservice.yaml* 文件,设置该服务注册的服务中心
-
- ```yaml
- APPLICATION_ID: saga
- service_description:
- name: flight-booking-service
- version: 0.0.1
- servicecomb:
- service:
- registry:
- address: http://sc.servicecomb.io:30100
#此处选择使用ServiceComb的Service Center
- rest:
- address: 0.0.0.0:8080
- handler:
- chain:
- Consumer:
- default: loadbalance
- ```
-
- 在 *saga-demo/docker-compose.yaml* 设置部署脚本
- ```yaml
- version: '2.1'
-
- services:
- service-center: #此处选择使用ServiceComb的Service Center容器镜像
- image: "servicecomb/service-center"
- hostname: service-center
- ports:
- - "30100:30100"
-
- mysql: #此处选择使用5.7版本的mysql镜像
- image: "mysql/mysql-server:5.7"
- hostname: mysql
- environment:
- - MYSQL_ROOT_PASSWORD=password
- - MYSQL_DATABASE=saga
- - MYSQL_USER=saga
- - MYSQL_PASSWORD=password
- ports:
- - "3306:3306"
- healthcheck:
- test: ["CMD-SHELL", "nc -z localhost 3306 &> /dev/null; echo
$$?"]
- interval: 30s
- timeout: 10s
- retries: 5
-
- car-rental-service:
- image: "car-rental-service:0.0.2-SNAPSHOT"
- hostname: car
- links:
- - "service-center:sc.servicecomb.io"
- ports:
- - "8080:8080"
-
- flight-booking-service:
- image: "flight-booking-service:0.0.2-SNAPSHOT"
- hostname: flight
- links:
- - "service-center:sc.servicecomb.io"
- ports:
- - "8081:8080"
-
- hotel-reservation-service:
- image: "hotel-reservation-service:0.0.2-SNAPSHOT"
- hostname: hotel
- links:
- - "service-center:sc.servicecomb.io"
- ports:
- - "8082:8080"
-
- payment-service:
- image: "payment-service:0.0.2-SNAPSHOT"
- hostname: payment
- links:
- - "service-center:sc.servicecomb.io"
- ports:
- - "8080"
-
- saga:
- image: "saga-spring:0.0.2-SNAPSHOT"
- hostname: saga
- links:
- - "mysql:mysql.servicecomb.io"
- - "service-center:sc.servicecomb.io"
- - "car-rental-service:car.servicecomb.io"
- - "flight-booking-service:flight.servicecomb.io"
- - "hotel-reservation-service:hotel.servicecomb.io"
- - "payment-service:payment.servicecomb.io"
- environment:
- - JAVA_OPTS=-Dspring.profiles.active=prd,servicecomb
-Dcse.service.registry.address=http://sc.servicecomb.io:30100
- ports:
- - "8083:8080"
- depends_on:
- mysql:
- condition: service_healthy
- ```
-
-3. 在Saga项目的根目录执行编译,制作Saga、机票预订、租车、酒店预订和支付服务镜像
-
- ```bash
- mvn package -DskipTests -Pdocker -Pdemo
- ```
-
-4. 在Saga项目的saga-demo目录通过docker-compose一键启动Saga、机票预订、租车、酒店预订和支付服务
-
- ```bash
- docker-compose up
- ```
-
-## 验证
-
-1. 参照 [Saga
API](https://github.com/apache/servicecomb-saga/blob/master/docs/api/api.md)
说明,设定各服务的事务、补偿、依赖和恢复参数,并保存为 *request.json* 文件
-
- ```json
- {
- "policy": "BackwardRecovery",
- "requests": [
- {
- "id": "request-car",
- "type": "rest",
- "serviceName": "car-rental-service",
- "transaction": {
- "method": "post",
- "path": "/rentals",
- "params": {
- "form": {
- "customerId": "mike"
- }
- }
- },
- "compensation": {
- "method": "put",
- "path": "/rentals",
- "params": {
- "form": {
- "customerId": "mike"
- }
- }
- }
- },
- {
- "id": "request-hotel",
- "type": "rest",
- "serviceName": "hotel-reservation-service",
- "transaction": {
- "method": "post",
- "path": "/reservations",
- "params": {
- "form": {
- "customerId": "mike"
- }
- }
- },
- "compensation": {
- "method": "put",
- "path": "/reservations",
- "params": {
- "form": {
- "customerId": "mike"
- }
- }
- }
- },
- {
- "id": "request-flight",
- "type": "rest",
- "serviceName": "flight-booking-service",
- "transaction": {
- "method": "post",
- "path": "/bookings",
- "params": {
- "form": {
- "customerId": "mike"
- }
- }
- },
- "compensation": {
- "method": "put",
- "path": "/bookings",
- "params": {
- "form": {
- "customerId": "mike"
- }
- }
- }
- },
- {
- "id": "request-payment",
- "type": "rest",
- "serviceName": "payment-service",
- "parents": [
- "request-car",
- "request-flight",
- "request-hotel"
- ],
- "transaction": {
- "method": "post",
- "path": "/payments",
- "params": {
- "form": {
- "customerId": "mike"
- }
- }
- },
- "compensation": {
- "method": "put",
- "path": "/payments",
- "params": {
- "form": {
- "customerId": "mike"
- }
- }
- }
- }
- ]
- }
- ```
-
-2. 发送请求到Saga
-
- ```bash
- curl -XPOST -H "Content-Type: text/plain" -d @./request.json
http://<localhost.ip:8083>/requests
- ```
-
- 获取处理结果成功(如果失败,返回相应的错误信息)
- ```bash
- success
- ```
-
-3. 查看Saga的事务
-
- ```bash
- curl -XGET http://<localhost.ip:8083>/events
- ```
-
- 查询结果
-
- ```bash
- {
- "bcd27f0d-6b82-49b3-8067-b16eba970e55": [
- {
- "id": 1,
- "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
- "creationTime": "2017-09-20T00:30:21Z",
- "type": "SagaStartedEvent",
- "contentJson": "{\"policy\": \"BackwardRecovery\",
\"requests\": [{\"id\": \"request-car\", \"type\": \"rest\", \"serviceName\":
\"car-rental-service\", \"transaction\": {\"path\": \"/rentals\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/rentals\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}}}, {\"id\": \"request-hotel\", \"type\":
\"rest\", \"serviceName\": \"hotel-reservation-servic [...]
- },
- {
- "id": 2,
- "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
- "creationTime": "2017-09-20T00:30:21Z",
- "type": "TransactionStartedEvent",
- "contentJson": "{\"id\": \"request-hotel\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"hotel-reservation-service\", \"transaction\": {\"path\": \"/reservations\",
\"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/reservations\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
- },
- {
- "id": 3,
- "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
- "creationTime": "2017-09-20T00:30:21Z",
- "type": "TransactionStartedEvent",
- "contentJson": "{\"id\": \"request-car\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"car-rental-service\", \"transaction\": {\"path\": \"/rentals\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/rentals\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
- },
- {
- "id": 4,
- "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
- "creationTime": "2017-09-20T00:30:21Z",
- "type": "TransactionStartedEvent",
- "contentJson": "{\"id\": \"request-flight\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"flight-booking-service\", \"transaction\": {\"path\": \"/bookings\",
\"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/bookings\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
- },
- {
- "id": 5,
- "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
- "creationTime": "2017-09-20T00:30:22Z",
- "type": "TransactionEndedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-flight\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"flight-booking-service\", \"transaction\": {\"path\":
\"/bookings\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/bookings\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\ [...]
- },
- {
- "id": 6,
- "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
- "creationTime": "2017-09-20T00:30:24Z",
- "type": "TransactionEndedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-hotel\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"hotel-reservation-service\", \"transaction\": {\"path\":
\"/reservations\", \"method\": \"post\", \"params\": {\"form\":
{\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/reservations\",
\"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}},
\"retries\": 3}}, \"response\": {\"body\": \"{\\n \\\"sta [...]
- },
- {
- "id": 7,
- "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
- "creationTime": "2017-09-20T00:30:25Z",
- "type": "TransactionEndedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-car\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"car-rental-service\", \"transaction\": {\"path\":
\"/rentals\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/rentals\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\": 200,\\ [...]
- },
- {
- "id": 8,
- "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
- "creationTime": "2017-09-20T00:30:25Z",
- "type": "TransactionStartedEvent",
- "contentJson": "{\"id\": \"request-payment\", \"type\":
\"rest\", \"parents\": [\"request-car\", \"request-flight\",
\"request-hotel\"], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"payment-service\", \"transaction\": {\"path\": \"/payments\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/payments\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
- },
- {
- "id": 9,
- "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
- "creationTime": "2017-09-20T00:30:25Z",
- "type": "TransactionEndedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-payment\",
\"type\": \"rest\", \"parents\": [\"request-car\", \"request-flight\",
\"request-hotel\"], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"payment-service\", \"transaction\": {\"path\": \"/payments\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/payments\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}, \" [...]
- },
- {
- "id": 10,
- "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
- "creationTime": "2017-09-20T00:30:25Z",
- "type": "SagaEndedEvent",
- "contentJson": "{}"
- }
- ]
- }
- ```
-
-4. demo中模拟了支付服务帐户余额不足场景,发送请求超过一次将触发补偿操作。再次发送请求,可以在Saga日志中找到补偿事件
-
- ```bash
- {
- "bcd27f0d-6b82-49b3-8067-b16eba970e55": [
- ...
- ],
- "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9": [
- {
- "id": 11,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:30:45Z",
- "type": "SagaStartedEvent",
- "contentJson": "{\"policy\": \"BackwardRecovery\",
\"requests\": [{\"id\": \"request-car\", \"type\": \"rest\", \"serviceName\":
\"car-rental-service\", \"transaction\": {\"path\": \"/rentals\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/rentals\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}}}, {\"id\": \"request-hotel\", \"type\":
\"rest\", \"serviceName\": \"hotel-reservation-servic [...]
- },
- {
- "id": 12,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:30:45Z",
- "type": "TransactionStartedEvent",
- "contentJson": "{\"id\": \"request-car\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"car-rental-service\", \"transaction\": {\"path\": \"/rentals\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/rentals\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
- },
- {
- "id": 13,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:30:45Z",
- "type": "TransactionStartedEvent",
- "contentJson": "{\"id\": \"request-hotel\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"hotel-reservation-service\", \"transaction\": {\"path\": \"/reservations\",
\"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/reservations\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
- },
- {
- "id": 14,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:30:45Z",
- "type": "TransactionStartedEvent",
- "contentJson": "{\"id\": \"request-flight\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"flight-booking-service\", \"transaction\": {\"path\": \"/bookings\",
\"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/bookings\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
- },
- {
- "id": 15,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:30:45Z",
- "type": "TransactionEndedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-car\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"car-rental-service\", \"transaction\": {\"path\":
\"/rentals\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/rentals\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\": 200,\\ [...]
- },
- {
- "id": 16,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:30:45Z",
- "type": "TransactionEndedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-hotel\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"hotel-reservation-service\", \"transaction\": {\"path\":
\"/reservations\", \"method\": \"post\", \"params\": {\"form\":
{\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/reservations\",
\"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}},
\"retries\": 3}}, \"response\": {\"body\": \"{\\n \\\"sta [...]
- },
- {
- "id": 17,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:30:45Z",
- "type": "TransactionEndedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-flight\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"flight-booking-service\", \"transaction\": {\"path\":
\"/bookings\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/bookings\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\ [...]
- },
- {
- "id": 18,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:30:45Z",
- "type": "TransactionStartedEvent",
- "contentJson": "{\"id\": \"request-payment\", \"type\":
\"rest\", \"parents\": [\"request-car\", \"request-flight\",
\"request-hotel\"], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"payment-service\", \"transaction\": {\"path\": \"/payments\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/payments\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
- },
- {
- "id": 19,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:31:15Z",
- "type": "TransactionAbortedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-payment\",
\"type\": \"rest\", \"parents\": [\"request-car\", \"request-flight\",
\"request-hotel\"], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"payment-service\", \"transaction\": {\"path\": \"/payments\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/payments\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}, \" [...]
- },
- {
- "id": 20,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:31:15Z",
- "type": "TransactionCompensatedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-car\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"car-rental-service\", \"transaction\": {\"path\":
\"/rentals\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/rentals\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\": 200,\\ [...]
- },
- {
- "id": 21,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:31:15Z",
- "type": "TransactionCompensatedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-hotel\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"hotel-reservation-service\", \"transaction\": {\"path\":
\"/reservations\", \"method\": \"post\", \"params\": {\"form\":
{\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/reservations\",
\"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}},
\"retries\": 3}}, \"response\": {\"body\": \"{\\n \\\"sta [...]
- },
- {
- "id": 22,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:31:15Z",
- "type": "TransactionCompensatedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-flight\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"flight-booking-service\", \"transaction\": {\"path\":
\"/bookings\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/bookings\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\ [...]
- },
- {
- "id": 23,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:31:15Z",
- "type": "SagaEndedEvent",
- "contentJson": "{}"
- }
- ]
- }
- ```
-
-## 下一步
-
-* 了解更多[ServiceComb中的数据最终一致性方案 - part 1](/cn/docs/distributed_saga_1/)
-
-* 了解更多[ServiceComb中的数据最终一致性方案 - part 2](/cn/docs/distributed_saga_2/)
-
-* 了解更多[ServiceComb中的数据最终一致性方案 - part 3](/cn/docs/distributed_saga_3/)
+---
+title: "数据一致性解决方案"
+lang: cn
+ref: quick-start-dataconsistency
+permalink: /cn/docs/quick-start-dataconsistency/
+excerpt: "介绍ServiceComb的Saga数据一致性方案应用demo"
+last_modified_at: 2017-09-19T11:50:10-04:00
+---
+
+{% include toc %}
+模拟一个简单的旅行应用,展示如何使用ServiceComb提供的Saga方案保证微服务间数据一致性。
+
+旅行应用包含四个微服务:
+- 机票预订服务(flight-booking-service)
+- 租车服务(car-rental-service)
+- 酒店预订服务(hotel-reservation-service)
+- 支付服务(payment-service)
+
+机票预订、租车、酒店预订服务间无依赖关系,使用自己的数据库,通过HTTP协议通信。
+在以上三个服务的预订成功,支付完成后才能满足一个成功的行程,否则不能成行,Saga自动补偿。
+
+
+
+## 运行demo
+
+注:Demo 集成在 [ServiceComb-Saga](https://github.com/apache/servicecomb-saga) 项目中。
+
+1. 准备环境
+- [Oracle JDK
1.8](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
+- [Maven 3.x](https://maven.apache.org/install.html)
+- [Docker](https://www.docker.com/get-docker)
+- [MySQL](https://dev.mysql.com/downloads/)
+- [Service Center](https://github.com/apache/servicecomb-service-center)
+- [Docker compose](https://docs.docker.com/compose/install/)
+
+2. 配置服务
+ 在各服务的 *microservice.yaml* 文件,设置该服务注册的服务中心
+
+ ```yaml
+ APPLICATION_ID: saga
+ service_description:
+ name: flight-booking-service
+ version: 0.0.1
+ servicecomb:
+ service:
+ registry:
+ address: http://sc.servicecomb.io:30100
#此处选择使用ServiceComb的Service Center
+ rest:
+ address: 0.0.0.0:8080
+ handler:
+ chain:
+ Consumer:
+ default: loadbalance
+ ```
+
+ 在 *saga-demo/docker-compose.yaml* 设置部署脚本
+ ```yaml
+ version: '2.1'
+
+ services:
+ service-center: #此处选择使用ServiceComb的Service Center容器镜像
+ image: "servicecomb/service-center"
+ hostname: service-center
+ ports:
+ - "30100:30100"
+
+ mysql: #此处选择使用5.7版本的mysql镜像
+ image: "mysql/mysql-server:5.7"
+ hostname: mysql
+ environment:
+ - MYSQL_ROOT_PASSWORD=password
+ - MYSQL_DATABASE=saga
+ - MYSQL_USER=saga
+ - MYSQL_PASSWORD=password
+ ports:
+ - "3306:3306"
+ healthcheck:
+ test: ["CMD-SHELL", "nc -z localhost 3306 &> /dev/null; echo
$$?"]
+ interval: 30s
+ timeout: 10s
+ retries: 5
+
+ car-rental-service:
+ image: "car-rental-service:0.0.2-SNAPSHOT"
+ hostname: car
+ links:
+ - "service-center:sc.servicecomb.io"
+ ports:
+ - "8080:8080"
+
+ flight-booking-service:
+ image: "flight-booking-service:0.0.2-SNAPSHOT"
+ hostname: flight
+ links:
+ - "service-center:sc.servicecomb.io"
+ ports:
+ - "8081:8080"
+
+ hotel-reservation-service:
+ image: "hotel-reservation-service:0.0.2-SNAPSHOT"
+ hostname: hotel
+ links:
+ - "service-center:sc.servicecomb.io"
+ ports:
+ - "8082:8080"
+
+ payment-service:
+ image: "payment-service:0.0.2-SNAPSHOT"
+ hostname: payment
+ links:
+ - "service-center:sc.servicecomb.io"
+ ports:
+ - "8080"
+
+ saga:
+ image: "saga-spring:0.0.2-SNAPSHOT"
+ hostname: saga
+ links:
+ - "mysql:mysql.servicecomb.io"
+ - "service-center:sc.servicecomb.io"
+ - "car-rental-service:car.servicecomb.io"
+ - "flight-booking-service:flight.servicecomb.io"
+ - "hotel-reservation-service:hotel.servicecomb.io"
+ - "payment-service:payment.servicecomb.io"
+ environment:
+ - JAVA_OPTS=-Dspring.profiles.active=prd,servicecomb
-Dcse.service.registry.address=http://sc.servicecomb.io:30100
+ ports:
+ - "8083:8080"
+ depends_on:
+ mysql:
+ condition: service_healthy
+ ```
+
+3. 在Saga项目的根目录执行编译,制作Saga、机票预订、租车、酒店预订和支付服务镜像
+
+ ```bash
+ mvn package -DskipTests -Pdocker -Pdemo
+ ```
+
+4. 在Saga项目的saga-demo目录通过docker-compose一键启动Saga、机票预订、租车、酒店预订和支付服务
+
+ ```bash
+ docker-compose up
+ ```
+
+## 验证
+
+1. 参照 [Saga
API](https://github.com/apache/servicecomb-saga/blob/master/docs/api/api.md)
说明,设定各服务的事务、补偿、依赖和恢复参数,并保存为 *request.json* 文件
+
+ ```json
+ {
+ "policy": "BackwardRecovery",
+ "requests": [
+ {
+ "id": "request-car",
+ "type": "rest",
+ "serviceName": "car-rental-service",
+ "transaction": {
+ "method": "post",
+ "path": "/rentals",
+ "params": {
+ "form": {
+ "customerId": "mike"
+ }
+ }
+ },
+ "compensation": {
+ "method": "put",
+ "path": "/rentals",
+ "params": {
+ "form": {
+ "customerId": "mike"
+ }
+ }
+ }
+ },
+ {
+ "id": "request-hotel",
+ "type": "rest",
+ "serviceName": "hotel-reservation-service",
+ "transaction": {
+ "method": "post",
+ "path": "/reservations",
+ "params": {
+ "form": {
+ "customerId": "mike"
+ }
+ }
+ },
+ "compensation": {
+ "method": "put",
+ "path": "/reservations",
+ "params": {
+ "form": {
+ "customerId": "mike"
+ }
+ }
+ }
+ },
+ {
+ "id": "request-flight",
+ "type": "rest",
+ "serviceName": "flight-booking-service",
+ "transaction": {
+ "method": "post",
+ "path": "/bookings",
+ "params": {
+ "form": {
+ "customerId": "mike"
+ }
+ }
+ },
+ "compensation": {
+ "method": "put",
+ "path": "/bookings",
+ "params": {
+ "form": {
+ "customerId": "mike"
+ }
+ }
+ }
+ },
+ {
+ "id": "request-payment",
+ "type": "rest",
+ "serviceName": "payment-service",
+ "parents": [
+ "request-car",
+ "request-flight",
+ "request-hotel"
+ ],
+ "transaction": {
+ "method": "post",
+ "path": "/payments",
+ "params": {
+ "form": {
+ "customerId": "mike"
+ }
+ }
+ },
+ "compensation": {
+ "method": "put",
+ "path": "/payments",
+ "params": {
+ "form": {
+ "customerId": "mike"
+ }
+ }
+ }
+ }
+ ]
+ }
+ ```
+
+2. 发送请求到Saga
+
+ ```bash
+ curl -XPOST -H "Content-Type: text/plain" -d @./request.json
http://<localhost.ip:8083>/requests
+ ```
+
+ 获取处理结果成功(如果失败,返回相应的错误信息)
+ ```bash
+ success
+ ```
+
+3. 查看Saga的事务
+
+ ```bash
+ curl -XGET http://<localhost.ip:8083>/events
+ ```
+
+ 查询结果
+
+ ```bash
+ {
+ "bcd27f0d-6b82-49b3-8067-b16eba970e55": [
+ {
+ "id": 1,
+ "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
+ "creationTime": "2017-09-20T00:30:21Z",
+ "type": "SagaStartedEvent",
+ "contentJson": "{\"policy\": \"BackwardRecovery\",
\"requests\": [{\"id\": \"request-car\", \"type\": \"rest\", \"serviceName\":
\"car-rental-service\", \"transaction\": {\"path\": \"/rentals\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/rentals\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}}}, {\"id\": \"request-hotel\", \"type\":
\"rest\", \"serviceName\": \"hotel-reservation-servic [...]
+ },
+ {
+ "id": 2,
+ "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
+ "creationTime": "2017-09-20T00:30:21Z",
+ "type": "TransactionStartedEvent",
+ "contentJson": "{\"id\": \"request-hotel\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"hotel-reservation-service\", \"transaction\": {\"path\": \"/reservations\",
\"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/reservations\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
+ },
+ {
+ "id": 3,
+ "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
+ "creationTime": "2017-09-20T00:30:21Z",
+ "type": "TransactionStartedEvent",
+ "contentJson": "{\"id\": \"request-car\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"car-rental-service\", \"transaction\": {\"path\": \"/rentals\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/rentals\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
+ },
+ {
+ "id": 4,
+ "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
+ "creationTime": "2017-09-20T00:30:21Z",
+ "type": "TransactionStartedEvent",
+ "contentJson": "{\"id\": \"request-flight\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"flight-booking-service\", \"transaction\": {\"path\": \"/bookings\",
\"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/bookings\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
+ },
+ {
+ "id": 5,
+ "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
+ "creationTime": "2017-09-20T00:30:22Z",
+ "type": "TransactionEndedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-flight\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"flight-booking-service\", \"transaction\": {\"path\":
\"/bookings\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/bookings\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\ [...]
+ },
+ {
+ "id": 6,
+ "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
+ "creationTime": "2017-09-20T00:30:24Z",
+ "type": "TransactionEndedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-hotel\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"hotel-reservation-service\", \"transaction\": {\"path\":
\"/reservations\", \"method\": \"post\", \"params\": {\"form\":
{\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/reservations\",
\"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}},
\"retries\": 3}}, \"response\": {\"body\": \"{\\n \\\"sta [...]
+ },
+ {
+ "id": 7,
+ "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
+ "creationTime": "2017-09-20T00:30:25Z",
+ "type": "TransactionEndedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-car\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"car-rental-service\", \"transaction\": {\"path\":
\"/rentals\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/rentals\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\": 200,\\ [...]
+ },
+ {
+ "id": 8,
+ "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
+ "creationTime": "2017-09-20T00:30:25Z",
+ "type": "TransactionStartedEvent",
+ "contentJson": "{\"id\": \"request-payment\", \"type\":
\"rest\", \"parents\": [\"request-car\", \"request-flight\",
\"request-hotel\"], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"payment-service\", \"transaction\": {\"path\": \"/payments\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/payments\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
+ },
+ {
+ "id": 9,
+ "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
+ "creationTime": "2017-09-20T00:30:25Z",
+ "type": "TransactionEndedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-payment\",
\"type\": \"rest\", \"parents\": [\"request-car\", \"request-flight\",
\"request-hotel\"], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"payment-service\", \"transaction\": {\"path\": \"/payments\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/payments\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}, \" [...]
+ },
+ {
+ "id": 10,
+ "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
+ "creationTime": "2017-09-20T00:30:25Z",
+ "type": "SagaEndedEvent",
+ "contentJson": "{}"
+ }
+ ]
+ }
+ ```
+
+4. demo中模拟了支付服务帐户余额不足场景,发送请求超过一次将触发补偿操作。再次发送请求,可以在Saga日志中找到补偿事件
+
+ ```bash
+ {
+ "bcd27f0d-6b82-49b3-8067-b16eba970e55": [
+ ...
+ ],
+ "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9": [
+ {
+ "id": 11,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:30:45Z",
+ "type": "SagaStartedEvent",
+ "contentJson": "{\"policy\": \"BackwardRecovery\",
\"requests\": [{\"id\": \"request-car\", \"type\": \"rest\", \"serviceName\":
\"car-rental-service\", \"transaction\": {\"path\": \"/rentals\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/rentals\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}}}, {\"id\": \"request-hotel\", \"type\":
\"rest\", \"serviceName\": \"hotel-reservation-servic [...]
+ },
+ {
+ "id": 12,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:30:45Z",
+ "type": "TransactionStartedEvent",
+ "contentJson": "{\"id\": \"request-car\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"car-rental-service\", \"transaction\": {\"path\": \"/rentals\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/rentals\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
+ },
+ {
+ "id": 13,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:30:45Z",
+ "type": "TransactionStartedEvent",
+ "contentJson": "{\"id\": \"request-hotel\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"hotel-reservation-service\", \"transaction\": {\"path\": \"/reservations\",
\"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/reservations\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
+ },
+ {
+ "id": 14,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:30:45Z",
+ "type": "TransactionStartedEvent",
+ "contentJson": "{\"id\": \"request-flight\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"flight-booking-service\", \"transaction\": {\"path\": \"/bookings\",
\"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/bookings\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
+ },
+ {
+ "id": 15,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:30:45Z",
+ "type": "TransactionEndedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-car\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"car-rental-service\", \"transaction\": {\"path\":
\"/rentals\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/rentals\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\": 200,\\ [...]
+ },
+ {
+ "id": 16,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:30:45Z",
+ "type": "TransactionEndedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-hotel\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"hotel-reservation-service\", \"transaction\": {\"path\":
\"/reservations\", \"method\": \"post\", \"params\": {\"form\":
{\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/reservations\",
\"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}},
\"retries\": 3}}, \"response\": {\"body\": \"{\\n \\\"sta [...]
+ },
+ {
+ "id": 17,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:30:45Z",
+ "type": "TransactionEndedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-flight\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"flight-booking-service\", \"transaction\": {\"path\":
\"/bookings\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/bookings\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\ [...]
+ },
+ {
+ "id": 18,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:30:45Z",
+ "type": "TransactionStartedEvent",
+ "contentJson": "{\"id\": \"request-payment\", \"type\":
\"rest\", \"parents\": [\"request-car\", \"request-flight\",
\"request-hotel\"], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"payment-service\", \"transaction\": {\"path\": \"/payments\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/payments\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
+ },
+ {
+ "id": 19,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:31:15Z",
+ "type": "TransactionAbortedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-payment\",
\"type\": \"rest\", \"parents\": [\"request-car\", \"request-flight\",
\"request-hotel\"], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"payment-service\", \"transaction\": {\"path\": \"/payments\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/payments\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}, \" [...]
+ },
+ {
+ "id": 20,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:31:15Z",
+ "type": "TransactionCompensatedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-car\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"car-rental-service\", \"transaction\": {\"path\":
\"/rentals\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/rentals\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\": 200,\\ [...]
+ },
+ {
+ "id": 21,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:31:15Z",
+ "type": "TransactionCompensatedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-hotel\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"hotel-reservation-service\", \"transaction\": {\"path\":
\"/reservations\", \"method\": \"post\", \"params\": {\"form\":
{\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/reservations\",
\"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}},
\"retries\": 3}}, \"response\": {\"body\": \"{\\n \\\"sta [...]
+ },
+ {
+ "id": 22,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:31:15Z",
+ "type": "TransactionCompensatedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-flight\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"flight-booking-service\", \"transaction\": {\"path\":
\"/bookings\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/bookings\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\ [...]
+ },
+ {
+ "id": 23,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:31:15Z",
+ "type": "SagaEndedEvent",
+ "contentJson": "{}"
+ }
+ ]
+ }
+ ```
+
+## 下一步
+
+* 了解更多[ServiceComb中的数据最终一致性方案 - part 1](/cn/docs/distributed_saga_1/)
+
+* 了解更多[ServiceComb中的数据最终一致性方案 - part 2](/cn/docs/distributed_saga_2/)
+
+* 了解更多[ServiceComb中的数据最终一致性方案 - part 3](/cn/docs/distributed_saga_3/)
diff --git a/_docs/quick-start-dataconsistency.md
b/_docs/quick-start-dataconsistency.md
index a8a17ec..be2a0f3 100755
--- a/_docs/quick-start-dataconsistency.md
+++ b/_docs/quick-start-dataconsistency.md
@@ -1,462 +1,462 @@
----
-title: "Data consistency solution"
-lang: en
-ref: quick-start-dataconsistency
-permalink: /docs/quick-start-dataconsistency/
-excerpt: "Introduce how to use Saga data consistency solution provided by
ServiceComb"
-last_modified_at: 2017-09-03T10:01:43-04:00
----
-
-{% include toc %}
-This demo shows you how to use the Saga solution provided by ServiceComb to
ensure the microservice for data consistency.
-
-With microservice architecture, each of the services may have its own database
technology and it's not feasible to ensure all transactions on these services
are either committed or rolled back with database. In this demo, we make use of
Saga to ensure eventual data consistency among services, the payment is only
executed after car rental, flight booking, and hotel-reservation are completed.
-
-Travel application demo including four services
-- flight booking service
-- car rental service
-- hotel reservation service
-- payment service
-
-
-
-## Running Demo
-
-Note, demo is in the
[ServiceComb-Saga](https://github.com/apache/servicecomb-saga) project.
-
-1. Prerequisites
-- [Oracle JDK
1.8](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
-- [Maven 3.x](https://maven.apache.org/install.html)
-- [Docker](https://www.docker.com/get-docker)
-- [MySQL](https://dev.mysql.com/downloads/)
-- [Service Center](https://github.com/apache/servicecomb-service-center)
-- [Docker compose](https://docs.docker.com/compose/install/)
-
-2. Configuration
- Set service center address of each microservice in *microservice.yaml*
file
-
- ```yaml
- APPLICATION_ID: saga
- service_description:
- name: flight-booking-service
- version: 0.0.1
- servicecomb:
- service:
- registry:
- address: http://sc.servicecomb.io:30100 #choose Service Center
provided by ServiceComb
- rest:
- address: 0.0.0.0:8080
- handler:
- chain:
- Consumer:
- default: loadbalance
- ```
-
- Set deployment script in *saga-demo/docker-compose.yaml* file
-
- ```yaml
- version: '2.1'
-
- services:
- service-center: #choose Service Center image provided by ServiceComb
- image: "servicecomb/service-center"
- hostname: service-center
- ports:
- - "30100:30100"
-
- mysql: #choose mysql image with 5.7 version
- image: "mysql/mysql-server:5.7"
- hostname: mysql
- environment:
- - MYSQL_ROOT_PASSWORD=password
- - MYSQL_DATABASE=saga
- - MYSQL_USER=saga
- - MYSQL_PASSWORD=password
- ports:
- - "3306:3306"
- healthcheck:
- test: ["CMD-SHELL", "nc -z localhost 3306 &> /dev/null; echo
$$?"]
- interval: 30s
- timeout: 10s
- retries: 5
-
- car-rental-service:
- image: "car-rental-service:0.0.2-SNAPSHOT"
- hostname: car
- links:
- - "service-center:sc.servicecomb.io"
- ports:
- - "8080:8080"
-
- flight-booking-service:
- image: "flight-booking-service:0.0.2-SNAPSHOT"
- hostname: flight
- links:
- - "service-center:sc.servicecomb.io"
- ports:
- - "8081:8080"
-
- hotel-reservation-service:
- image: "hotel-reservation-service:0.0.2-SNAPSHOT"
- hostname: hotel
- links:
- - "service-center:sc.servicecomb.io"
- ports:
- - "8082:8080"
-
- payment-service:
- image: "payment-service:0.0.2-SNAPSHOT"
- hostname: payment
- links:
- - "service-center:sc.servicecomb.io"
- ports:
- - "8080"
-
- saga:
- image: "saga-spring:0.0.2-SNAPSHOT"
- hostname: saga
- links:
- - "mysql:mysql.servicecomb.io"
- - "service-center:sc.servicecomb.io"
- - "car-rental-service:car.servicecomb.io"
- - "flight-booking-service:flight.servicecomb.io"
- - "hotel-reservation-service:hotel.servicecomb.io"
- - "payment-service:payment.servicecomb.io"
- environment:
- - JAVA_OPTS=-Dspring.profiles.active=prd,servicecomb
-Dcse.service.registry.address=http://sc.servicecomb.io:30100
- ports:
- - "8083:8080"
- depends_on:
- mysql:
- condition: service_healthy
- ```
-
-3. Run the following command to create docker images in saga project root
folder
-
- ```bash
- mvn package -DskipTests -Pdocker -Pdemo
- ```
-
-4. Start application up in saga/saga-demo/ with the following command
-
- ```bash
- docker-compose up
- ```
-
-## Verify services
-
-1. Use [Saga
API](https://github.com/apache/servicecomb-saga/blob/master/docs/api/api.md) to
set request content and save it to *request.json*
-
- ```json
- {
- "policy": "BackwardRecovery",
- "requests": [
- {
- "id": "request-car",
- "type": "rest",
- "serviceName": "car-rental-service",
- "transaction": {
- "method": "post",
- "path": "/rentals",
- "params": {
- "form": {
- "customerId": "mike"
- }
- }
- },
- "compensation": {
- "method": "put",
- "path": "/rentals",
- "params": {
- "form": {
- "customerId": "mike"
- }
- }
- }
- },
- {
- "id": "request-hotel",
- "type": "rest",
- "serviceName": "hotel-reservation-service",
- "transaction": {
- "method": "post",
- "path": "/reservations",
- "params": {
- "form": {
- "customerId": "mike"
- }
- }
- },
- "compensation": {
- "method": "put",
- "path": "/reservations",
- "params": {
- "form": {
- "customerId": "mike"
- }
- }
- }
- },
- {
- "id": "request-flight",
- "type": "rest",
- "serviceName": "flight-booking-service",
- "transaction": {
- "method": "post",
- "path": "/bookings",
- "params": {
- "form": {
- "customerId": "mike"
- }
- }
- },
- "compensation": {
- "method": "put",
- "path": "/bookings",
- "params": {
- "form": {
- "customerId": "mike"
- }
- }
- }
- },
- {
- "id": "request-payment",
- "type": "rest",
- "serviceName": "payment-service",
- "parents": [
- "request-car",
- "request-flight",
- "request-hotel"
- ],
- "transaction": {
- "method": "post",
- "path": "/payments",
- "params": {
- "form": {
- "customerId": "mike"
- }
- }
- },
- "compensation": {
- "method": "put",
- "path": "/payments",
- "params": {
- "form": {
- "customerId": "mike"
- }
- }
- }
- }
- ]
- }
- ```
-
-2. Set content type to *text/plain*, and send *request.json* to Saga
-
- ```bash
- curl -XPOST -H "Content-Type: text/plain" -d @./request.json
http://<localhost.ip:8083>/requests
- ```
-
- Response(return "success" if execution successfully, otherwise return
failed with error info)
-
- ```bash
- success
- ```
-
-3. Get all the Saga events
-
- ```bash
- curl -XGET http://<localhost.ip:8083>/events
- ```
-
- Response
-
- ```bash
- {
- "bcd27f0d-6b82-49b3-8067-b16eba970e55": [
- {
- "id": 1,
- "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
- "creationTime": "2017-09-20T00:30:21Z",
- "type": "SagaStartedEvent",
- "contentJson": "{\"policy\": \"BackwardRecovery\",
\"requests\": [{\"id\": \"request-car\", \"type\": \"rest\", \"serviceName\":
\"car-rental-service\", \"transaction\": {\"path\": \"/rentals\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/rentals\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}}}, {\"id\": \"request-hotel\", \"type\":
\"rest\", \"serviceName\": \"hotel-reservation-servic [...]
- },
- {
- "id": 2,
- "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
- "creationTime": "2017-09-20T00:30:21Z",
- "type": "TransactionStartedEvent",
- "contentJson": "{\"id\": \"request-hotel\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"hotel-reservation-service\", \"transaction\": {\"path\": \"/reservations\",
\"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/reservations\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
- },
- {
- "id": 3,
- "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
- "creationTime": "2017-09-20T00:30:21Z",
- "type": "TransactionStartedEvent",
- "contentJson": "{\"id\": \"request-car\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"car-rental-service\", \"transaction\": {\"path\": \"/rentals\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/rentals\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
- },
- {
- "id": 4,
- "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
- "creationTime": "2017-09-20T00:30:21Z",
- "type": "TransactionStartedEvent",
- "contentJson": "{\"id\": \"request-flight\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"flight-booking-service\", \"transaction\": {\"path\": \"/bookings\",
\"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/bookings\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
- },
- {
- "id": 5,
- "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
- "creationTime": "2017-09-20T00:30:22Z",
- "type": "TransactionEndedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-flight\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"flight-booking-service\", \"transaction\": {\"path\":
\"/bookings\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/bookings\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\ [...]
- },
- {
- "id": 6,
- "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
- "creationTime": "2017-09-20T00:30:24Z",
- "type": "TransactionEndedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-hotel\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"hotel-reservation-service\", \"transaction\": {\"path\":
\"/reservations\", \"method\": \"post\", \"params\": {\"form\":
{\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/reservations\",
\"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}},
\"retries\": 3}}, \"response\": {\"body\": \"{\\n \\\"sta [...]
- },
- {
- "id": 7,
- "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
- "creationTime": "2017-09-20T00:30:25Z",
- "type": "TransactionEndedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-car\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"car-rental-service\", \"transaction\": {\"path\":
\"/rentals\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/rentals\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\": 200,\\ [...]
- },
- {
- "id": 8,
- "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
- "creationTime": "2017-09-20T00:30:25Z",
- "type": "TransactionStartedEvent",
- "contentJson": "{\"id\": \"request-payment\", \"type\":
\"rest\", \"parents\": [\"request-car\", \"request-flight\",
\"request-hotel\"], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"payment-service\", \"transaction\": {\"path\": \"/payments\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/payments\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
- },
- {
- "id": 9,
- "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
- "creationTime": "2017-09-20T00:30:25Z",
- "type": "TransactionEndedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-payment\",
\"type\": \"rest\", \"parents\": [\"request-car\", \"request-flight\",
\"request-hotel\"], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"payment-service\", \"transaction\": {\"path\": \"/payments\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/payments\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}, \" [...]
- },
- {
- "id": 10,
- "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
- "creationTime": "2017-09-20T00:30:25Z",
- "type": "SagaEndedEvent",
- "contentJson": "{}"
- }
- ]
- }
- ```
-
-4. Sending the request more than once will trigger compensation due to
insufficient account balance in payment-service.Do this implement and get Saga
events, you can find compensation events in Saga log.
-
- ```bash
- {
- "bcd27f0d-6b82-49b3-8067-b16eba970e55": [
- ...
- ],
- "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9": [
- {
- "id": 11,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:30:45Z",
- "type": "SagaStartedEvent",
- "contentJson": "{\"policy\": \"BackwardRecovery\",
\"requests\": [{\"id\": \"request-car\", \"type\": \"rest\", \"serviceName\":
\"car-rental-service\", \"transaction\": {\"path\": \"/rentals\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/rentals\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}}}, {\"id\": \"request-hotel\", \"type\":
\"rest\", \"serviceName\": \"hotel-reservation-servic [...]
- },
- {
- "id": 12,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:30:45Z",
- "type": "TransactionStartedEvent",
- "contentJson": "{\"id\": \"request-car\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"car-rental-service\", \"transaction\": {\"path\": \"/rentals\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/rentals\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
- },
- {
- "id": 13,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:30:45Z",
- "type": "TransactionStartedEvent",
- "contentJson": "{\"id\": \"request-hotel\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"hotel-reservation-service\", \"transaction\": {\"path\": \"/reservations\",
\"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/reservations\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
- },
- {
- "id": 14,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:30:45Z",
- "type": "TransactionStartedEvent",
- "contentJson": "{\"id\": \"request-flight\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"flight-booking-service\", \"transaction\": {\"path\": \"/bookings\",
\"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/bookings\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
- },
- {
- "id": 15,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:30:45Z",
- "type": "TransactionEndedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-car\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"car-rental-service\", \"transaction\": {\"path\":
\"/rentals\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/rentals\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\": 200,\\ [...]
- },
- {
- "id": 16,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:30:45Z",
- "type": "TransactionEndedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-hotel\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"hotel-reservation-service\", \"transaction\": {\"path\":
\"/reservations\", \"method\": \"post\", \"params\": {\"form\":
{\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/reservations\",
\"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}},
\"retries\": 3}}, \"response\": {\"body\": \"{\\n \\\"sta [...]
- },
- {
- "id": 17,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:30:45Z",
- "type": "TransactionEndedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-flight\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"flight-booking-service\", \"transaction\": {\"path\":
\"/bookings\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/bookings\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\ [...]
- },
- {
- "id": 18,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:30:45Z",
- "type": "TransactionStartedEvent",
- "contentJson": "{\"id\": \"request-payment\", \"type\":
\"rest\", \"parents\": [\"request-car\", \"request-flight\",
\"request-hotel\"], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"payment-service\", \"transaction\": {\"path\": \"/payments\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/payments\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
- },
- {
- "id": 19,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:31:15Z",
- "type": "TransactionAbortedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-payment\",
\"type\": \"rest\", \"parents\": [\"request-car\", \"request-flight\",
\"request-hotel\"], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"payment-service\", \"transaction\": {\"path\": \"/payments\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/payments\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}, \" [...]
- },
- {
- "id": 20,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:31:15Z",
- "type": "TransactionCompensatedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-car\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"car-rental-service\", \"transaction\": {\"path\":
\"/rentals\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/rentals\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\": 200,\\ [...]
- },
- {
- "id": 21,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:31:15Z",
- "type": "TransactionCompensatedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-hotel\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"hotel-reservation-service\", \"transaction\": {\"path\":
\"/reservations\", \"method\": \"post\", \"params\": {\"form\":
{\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/reservations\",
\"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}},
\"retries\": 3}}, \"response\": {\"body\": \"{\\n \\\"sta [...]
- },
- {
- "id": 22,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:31:15Z",
- "type": "TransactionCompensatedEvent",
- "contentJson": "{\"request\": {\"id\": \"request-flight\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"flight-booking-service\", \"transaction\": {\"path\":
\"/bookings\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/bookings\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\ [...]
- },
- {
- "id": 23,
- "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
- "creationTime": "2017-09-20T00:31:15Z",
- "type": "SagaEndedEvent",
- "contentJson": "{}"
- }
- ]
- }
- ```
-
-
-## What's next
-
-* Learn more from [Eventual Data Consistency Solution in ServiceComb - part
1](/docs/distributed_saga_1/)
-
-* Learn more from [Eventual Data Consistency Solution in ServiceComb - part
2](/docs/distributed_saga_2/)
-
-* Learn more from [Eventual Data Consistency Solution in ServiceComb - part
3](/docs/distributed_saga_3/)
+---
+title: "Data consistency solution"
+lang: en
+ref: quick-start-dataconsistency
+permalink: /docs/quick-start-dataconsistency/
+excerpt: "Introduce how to use Saga data consistency solution provided by
ServiceComb"
+last_modified_at: 2017-09-03T10:01:43-04:00
+---
+
+{% include toc %}
+This demo shows you how to use the Saga solution provided by ServiceComb to
ensure the microservice for data consistency.
+
+With microservice architecture, each of the services may have its own database
technology and it's not feasible to ensure all transactions on these services
are either committed or rolled back with database. In this demo, we make use of
Saga to ensure eventual data consistency among services, the payment is only
executed after car rental, flight booking, and hotel-reservation are completed.
+
+Travel application demo including four services
+- flight booking service
+- car rental service
+- hotel reservation service
+- payment service
+
+
+
+## Running Demo
+
+Note, demo is in the
[ServiceComb-Saga](https://github.com/apache/servicecomb-saga) project.
+
+1. Prerequisites
+- [Oracle JDK
1.8](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
+- [Maven 3.x](https://maven.apache.org/install.html)
+- [Docker](https://www.docker.com/get-docker)
+- [MySQL](https://dev.mysql.com/downloads/)
+- [Service Center](https://github.com/apache/servicecomb-service-center)
+- [Docker compose](https://docs.docker.com/compose/install/)
+
+2. Configuration
+ Set service center address of each microservice in *microservice.yaml*
file
+
+ ```yaml
+ APPLICATION_ID: saga
+ service_description:
+ name: flight-booking-service
+ version: 0.0.1
+ servicecomb:
+ service:
+ registry:
+ address: http://sc.servicecomb.io:30100 #choose Service Center
provided by ServiceComb
+ rest:
+ address: 0.0.0.0:8080
+ handler:
+ chain:
+ Consumer:
+ default: loadbalance
+ ```
+
+ Set deployment script in *saga-demo/docker-compose.yaml* file
+
+ ```yaml
+ version: '2.1'
+
+ services:
+ service-center: #choose Service Center image provided by ServiceComb
+ image: "servicecomb/service-center"
+ hostname: service-center
+ ports:
+ - "30100:30100"
+
+ mysql: #choose mysql image with 5.7 version
+ image: "mysql/mysql-server:5.7"
+ hostname: mysql
+ environment:
+ - MYSQL_ROOT_PASSWORD=password
+ - MYSQL_DATABASE=saga
+ - MYSQL_USER=saga
+ - MYSQL_PASSWORD=password
+ ports:
+ - "3306:3306"
+ healthcheck:
+ test: ["CMD-SHELL", "nc -z localhost 3306 &> /dev/null; echo
$$?"]
+ interval: 30s
+ timeout: 10s
+ retries: 5
+
+ car-rental-service:
+ image: "car-rental-service:0.0.2-SNAPSHOT"
+ hostname: car
+ links:
+ - "service-center:sc.servicecomb.io"
+ ports:
+ - "8080:8080"
+
+ flight-booking-service:
+ image: "flight-booking-service:0.0.2-SNAPSHOT"
+ hostname: flight
+ links:
+ - "service-center:sc.servicecomb.io"
+ ports:
+ - "8081:8080"
+
+ hotel-reservation-service:
+ image: "hotel-reservation-service:0.0.2-SNAPSHOT"
+ hostname: hotel
+ links:
+ - "service-center:sc.servicecomb.io"
+ ports:
+ - "8082:8080"
+
+ payment-service:
+ image: "payment-service:0.0.2-SNAPSHOT"
+ hostname: payment
+ links:
+ - "service-center:sc.servicecomb.io"
+ ports:
+ - "8080"
+
+ saga:
+ image: "saga-spring:0.0.2-SNAPSHOT"
+ hostname: saga
+ links:
+ - "mysql:mysql.servicecomb.io"
+ - "service-center:sc.servicecomb.io"
+ - "car-rental-service:car.servicecomb.io"
+ - "flight-booking-service:flight.servicecomb.io"
+ - "hotel-reservation-service:hotel.servicecomb.io"
+ - "payment-service:payment.servicecomb.io"
+ environment:
+ - JAVA_OPTS=-Dspring.profiles.active=prd,servicecomb
-Dcse.service.registry.address=http://sc.servicecomb.io:30100
+ ports:
+ - "8083:8080"
+ depends_on:
+ mysql:
+ condition: service_healthy
+ ```
+
+3. Run the following command to create docker images in saga project root
folder
+
+ ```bash
+ mvn package -DskipTests -Pdocker -Pdemo
+ ```
+
+4. Start application up in saga/saga-demo/ with the following command
+
+ ```bash
+ docker-compose up
+ ```
+
+## Verify services
+
+1. Use [Saga
API](https://github.com/apache/servicecomb-saga/blob/master/docs/api/api.md) to
set request content and save it to *request.json*
+
+ ```json
+ {
+ "policy": "BackwardRecovery",
+ "requests": [
+ {
+ "id": "request-car",
+ "type": "rest",
+ "serviceName": "car-rental-service",
+ "transaction": {
+ "method": "post",
+ "path": "/rentals",
+ "params": {
+ "form": {
+ "customerId": "mike"
+ }
+ }
+ },
+ "compensation": {
+ "method": "put",
+ "path": "/rentals",
+ "params": {
+ "form": {
+ "customerId": "mike"
+ }
+ }
+ }
+ },
+ {
+ "id": "request-hotel",
+ "type": "rest",
+ "serviceName": "hotel-reservation-service",
+ "transaction": {
+ "method": "post",
+ "path": "/reservations",
+ "params": {
+ "form": {
+ "customerId": "mike"
+ }
+ }
+ },
+ "compensation": {
+ "method": "put",
+ "path": "/reservations",
+ "params": {
+ "form": {
+ "customerId": "mike"
+ }
+ }
+ }
+ },
+ {
+ "id": "request-flight",
+ "type": "rest",
+ "serviceName": "flight-booking-service",
+ "transaction": {
+ "method": "post",
+ "path": "/bookings",
+ "params": {
+ "form": {
+ "customerId": "mike"
+ }
+ }
+ },
+ "compensation": {
+ "method": "put",
+ "path": "/bookings",
+ "params": {
+ "form": {
+ "customerId": "mike"
+ }
+ }
+ }
+ },
+ {
+ "id": "request-payment",
+ "type": "rest",
+ "serviceName": "payment-service",
+ "parents": [
+ "request-car",
+ "request-flight",
+ "request-hotel"
+ ],
+ "transaction": {
+ "method": "post",
+ "path": "/payments",
+ "params": {
+ "form": {
+ "customerId": "mike"
+ }
+ }
+ },
+ "compensation": {
+ "method": "put",
+ "path": "/payments",
+ "params": {
+ "form": {
+ "customerId": "mike"
+ }
+ }
+ }
+ }
+ ]
+ }
+ ```
+
+2. Set content type to *text/plain*, and send *request.json* to Saga
+
+ ```bash
+ curl -XPOST -H "Content-Type: text/plain" -d @./request.json
http://<localhost.ip:8083>/requests
+ ```
+
+ Response(return "success" if execution successfully, otherwise return
failed with error info)
+
+ ```bash
+ success
+ ```
+
+3. Get all the Saga events
+
+ ```bash
+ curl -XGET http://<localhost.ip:8083>/events
+ ```
+
+ Response
+
+ ```bash
+ {
+ "bcd27f0d-6b82-49b3-8067-b16eba970e55": [
+ {
+ "id": 1,
+ "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
+ "creationTime": "2017-09-20T00:30:21Z",
+ "type": "SagaStartedEvent",
+ "contentJson": "{\"policy\": \"BackwardRecovery\",
\"requests\": [{\"id\": \"request-car\", \"type\": \"rest\", \"serviceName\":
\"car-rental-service\", \"transaction\": {\"path\": \"/rentals\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/rentals\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}}}, {\"id\": \"request-hotel\", \"type\":
\"rest\", \"serviceName\": \"hotel-reservation-servic [...]
+ },
+ {
+ "id": 2,
+ "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
+ "creationTime": "2017-09-20T00:30:21Z",
+ "type": "TransactionStartedEvent",
+ "contentJson": "{\"id\": \"request-hotel\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"hotel-reservation-service\", \"transaction\": {\"path\": \"/reservations\",
\"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/reservations\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
+ },
+ {
+ "id": 3,
+ "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
+ "creationTime": "2017-09-20T00:30:21Z",
+ "type": "TransactionStartedEvent",
+ "contentJson": "{\"id\": \"request-car\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"car-rental-service\", \"transaction\": {\"path\": \"/rentals\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/rentals\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
+ },
+ {
+ "id": 4,
+ "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
+ "creationTime": "2017-09-20T00:30:21Z",
+ "type": "TransactionStartedEvent",
+ "contentJson": "{\"id\": \"request-flight\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"flight-booking-service\", \"transaction\": {\"path\": \"/bookings\",
\"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/bookings\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
+ },
+ {
+ "id": 5,
+ "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
+ "creationTime": "2017-09-20T00:30:22Z",
+ "type": "TransactionEndedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-flight\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"flight-booking-service\", \"transaction\": {\"path\":
\"/bookings\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/bookings\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\ [...]
+ },
+ {
+ "id": 6,
+ "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
+ "creationTime": "2017-09-20T00:30:24Z",
+ "type": "TransactionEndedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-hotel\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"hotel-reservation-service\", \"transaction\": {\"path\":
\"/reservations\", \"method\": \"post\", \"params\": {\"form\":
{\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/reservations\",
\"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}},
\"retries\": 3}}, \"response\": {\"body\": \"{\\n \\\"sta [...]
+ },
+ {
+ "id": 7,
+ "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
+ "creationTime": "2017-09-20T00:30:25Z",
+ "type": "TransactionEndedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-car\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"car-rental-service\", \"transaction\": {\"path\":
\"/rentals\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/rentals\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\": 200,\\ [...]
+ },
+ {
+ "id": 8,
+ "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
+ "creationTime": "2017-09-20T00:30:25Z",
+ "type": "TransactionStartedEvent",
+ "contentJson": "{\"id\": \"request-payment\", \"type\":
\"rest\", \"parents\": [\"request-car\", \"request-flight\",
\"request-hotel\"], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"payment-service\", \"transaction\": {\"path\": \"/payments\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/payments\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
+ },
+ {
+ "id": 9,
+ "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
+ "creationTime": "2017-09-20T00:30:25Z",
+ "type": "TransactionEndedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-payment\",
\"type\": \"rest\", \"parents\": [\"request-car\", \"request-flight\",
\"request-hotel\"], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"payment-service\", \"transaction\": {\"path\": \"/payments\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/payments\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}, \" [...]
+ },
+ {
+ "id": 10,
+ "sagaId": "bcd27f0d-6b82-49b3-8067-b16eba970e55",
+ "creationTime": "2017-09-20T00:30:25Z",
+ "type": "SagaEndedEvent",
+ "contentJson": "{}"
+ }
+ ]
+ }
+ ```
+
+4. Sending the request more than once will trigger compensation due to
insufficient account balance in payment-service.Do this implement and get Saga
events, you can find compensation events in Saga log.
+
+ ```bash
+ {
+ "bcd27f0d-6b82-49b3-8067-b16eba970e55": [
+ ...
+ ],
+ "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9": [
+ {
+ "id": 11,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:30:45Z",
+ "type": "SagaStartedEvent",
+ "contentJson": "{\"policy\": \"BackwardRecovery\",
\"requests\": [{\"id\": \"request-car\", \"type\": \"rest\", \"serviceName\":
\"car-rental-service\", \"transaction\": {\"path\": \"/rentals\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/rentals\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}}}, {\"id\": \"request-hotel\", \"type\":
\"rest\", \"serviceName\": \"hotel-reservation-servic [...]
+ },
+ {
+ "id": 12,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:30:45Z",
+ "type": "TransactionStartedEvent",
+ "contentJson": "{\"id\": \"request-car\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"car-rental-service\", \"transaction\": {\"path\": \"/rentals\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/rentals\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
+ },
+ {
+ "id": 13,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:30:45Z",
+ "type": "TransactionStartedEvent",
+ "contentJson": "{\"id\": \"request-hotel\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"hotel-reservation-service\", \"transaction\": {\"path\": \"/reservations\",
\"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/reservations\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
+ },
+ {
+ "id": 14,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:30:45Z",
+ "type": "TransactionStartedEvent",
+ "contentJson": "{\"id\": \"request-flight\", \"type\":
\"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"flight-booking-service\", \"transaction\": {\"path\": \"/bookings\",
\"method\": \"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/bookings\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
+ },
+ {
+ "id": 15,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:30:45Z",
+ "type": "TransactionEndedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-car\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"car-rental-service\", \"transaction\": {\"path\":
\"/rentals\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/rentals\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\": 200,\\ [...]
+ },
+ {
+ "id": 16,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:30:45Z",
+ "type": "TransactionEndedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-hotel\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"hotel-reservation-service\", \"transaction\": {\"path\":
\"/reservations\", \"method\": \"post\", \"params\": {\"form\":
{\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/reservations\",
\"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}},
\"retries\": 3}}, \"response\": {\"body\": \"{\\n \\\"sta [...]
+ },
+ {
+ "id": 17,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:30:45Z",
+ "type": "TransactionEndedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-flight\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"flight-booking-service\", \"transaction\": {\"path\":
\"/bookings\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/bookings\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\ [...]
+ },
+ {
+ "id": 18,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:30:45Z",
+ "type": "TransactionStartedEvent",
+ "contentJson": "{\"id\": \"request-payment\", \"type\":
\"rest\", \"parents\": [\"request-car\", \"request-flight\",
\"request-hotel\"], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"payment-service\", \"transaction\": {\"path\": \"/payments\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/payments\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}"
+ },
+ {
+ "id": 19,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:31:15Z",
+ "type": "TransactionAbortedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-payment\",
\"type\": \"rest\", \"parents\": [\"request-car\", \"request-flight\",
\"request-hotel\"], \"fallback\": {\"type\": \"NOP\"}, \"serviceName\":
\"payment-service\", \"transaction\": {\"path\": \"/payments\", \"method\":
\"post\", \"params\": {\"form\": {\"customerId\": \"mike\"}}},
\"compensation\": {\"path\": \"/payments\", \"method\": \"put\", \"params\":
{\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}}, \" [...]
+ },
+ {
+ "id": 20,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:31:15Z",
+ "type": "TransactionCompensatedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-car\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"car-rental-service\", \"transaction\": {\"path\":
\"/rentals\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/rentals\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\": 200,\\ [...]
+ },
+ {
+ "id": 21,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:31:15Z",
+ "type": "TransactionCompensatedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-hotel\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"hotel-reservation-service\", \"transaction\": {\"path\":
\"/reservations\", \"method\": \"post\", \"params\": {\"form\":
{\"customerId\": \"mike\"}}}, \"compensation\": {\"path\": \"/reservations\",
\"method\": \"put\", \"params\": {\"form\": {\"customerId\": \"mike\"}},
\"retries\": 3}}, \"response\": {\"body\": \"{\\n \\\"sta [...]
+ },
+ {
+ "id": 22,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:31:15Z",
+ "type": "TransactionCompensatedEvent",
+ "contentJson": "{\"request\": {\"id\": \"request-flight\",
\"type\": \"rest\", \"parents\": [], \"fallback\": {\"type\": \"NOP\"},
\"serviceName\": \"flight-booking-service\", \"transaction\": {\"path\":
\"/bookings\", \"method\": \"post\", \"params\": {\"form\": {\"customerId\":
\"mike\"}}}, \"compensation\": {\"path\": \"/bookings\", \"method\": \"put\",
\"params\": {\"form\": {\"customerId\": \"mike\"}}, \"retries\": 3}},
\"response\": {\"body\": \"{\\n \\\"statusCode\\\ [...]
+ },
+ {
+ "id": 23,
+ "sagaId": "2654fa50-71e2-4fc8-afc2-6a5e0d3dafe9",
+ "creationTime": "2017-09-20T00:31:15Z",
+ "type": "SagaEndedEvent",
+ "contentJson": "{}"
+ }
+ ]
+ }
+ ```
+
+
+## What's next
+
+* Learn more from [Eventual Data Consistency Solution in ServiceComb - part
1](/docs/distributed_saga_1/)
+
+* Learn more from [Eventual Data Consistency Solution in ServiceComb - part
2](/docs/distributed_saga_2/)
+
+* Learn more from [Eventual Data Consistency Solution in ServiceComb - part
3](/docs/distributed_saga_3/)
diff --git a/_posts/cn/2018-04-04-saga-pack-design.md
b/_posts/cn/2018-04-04-saga-pack-design.md
index 11e2918..959b84f 100644
--- a/_posts/cn/2018-04-04-saga-pack-design.md
+++ b/_posts/cn/2018-04-04-saga-pack-design.md
@@ -99,12 +99,12 @@ omega的使用很简单,以一个简化的转账业务为例,同一笔转账
1. 引入依赖
```xml
<dependency>
- <groupId>org.apache.servicecomb.saga</groupId>
+ <groupId>org.apache.servicecomb.pack</groupId>
<artifactId>omega-spring-starter</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
- <groupId>org.apache.servicecomb.saga</groupId>
+ <groupId>org.apache.servicecomb.pack</groupId>
<artifactId>omega-transport-resttemplate</artifactId>
<version>0.1.0</version>
</dependency>
diff --git a/_posts/cn/2018-04-28-saga_with_cucumber.md
b/_posts/cn/2018-04-28-saga_with_cucumber.md
index 755dbb6..36807ec 100644
--- a/_posts/cn/2018-04-28-saga_with_cucumber.md
+++ b/_posts/cn/2018-04-28-saga_with_cucumber.md
@@ -207,7 +207,7 @@ Saga在Cucumber中集成了byteman注入一个超时异常,测试Saga对超时
```yaml
RULE set the saga timeout to 5s
- INTERFACE org.apache.servicecomb.saga.omega.context.annotations.SagaStart
+ INTERFACE org.apache.servicecomb.pack.omega.context.annotations.SagaStart
METHOD timeout
AT EXIT
IF TRUE
@@ -215,7 +215,7 @@ Saga在Cucumber中集成了byteman注入一个超时异常,测试Saga对超时
ENDRULE
RULE sleep when postBooking until timeout happens
- CLASS org.apache.servicecomb.saga.demo.pack.booking.BookingController
+ CLASS org.apache.servicecomb.pack.demo.pack.booking.BookingController
METHOD postBooking
AT ENTRY
IF TRUE