Получите исходный код:
$ git clone https://github.com/apache/servicecomb-pack.git
$ cd servicecomb-pack
Saga можно построить одним из следующих способов:
Только сборка исполняемого файла:
$ mvn clean install -DskipTests
Сборка исполняемого файла и образа Docker одновременно:
$ mvn clean install -DskipTests -Pdocker
Сборка исполняемого файла, а также пакета выпуска Saga:
$ mnv clean install -DskipTests -Prelease
После выполнения любой из этих команд вы можете найти исполняемый файл alpha server в alpha/alpha-server/target/saga/alpha-server-${version}-exec.jar
.
<dependency>
<groupId>org.apache.servicecomb.pack</groupId>
<artifactId>omega-spring-starter</artifactId>
<version>${pack.version}</version>
</dependency>
<dependency>
<groupId>org.apache.servicecomb.pack</groupId>
<artifactId>omega-transport-resttemplate</artifactId>
<version>${pack.version}</version>
</dependency>
Примечание: замените ${pack.version}
на фактический номер версии.
Совет по миграции версий: начиная с версии 0.3.0, имя всего проекта было изменено с servicecomb-saga на servicecomb-pack, и мы также обновили соответствующие имена групп и пакетов выпусков. Если ваш проект был перенесён из saga 0.2.x, выполните следующие изменения:
name | 0.2.x | 0.3.x |
---|---|---|
groupId | org.apache.servicecomb.saga | org.apache.servicecomb.pack |
Package Name | org.apache.servicecomb.saga | org.apache.servicecomb.pack |
Добавьте аннотации Saga и соответствующие методы компенсации: Рассмотрим пример приложения для перевода денег:
Добавьте аннотацию @SagaStart
к глобальному началу транзакции, чтобы Omega создал новую глобальную транзакцию. Если не пометить эту точку начала транзакции, дочерние транзакции будут выдавать ошибку при поиске глобального идентификатора транзакции во время выполнения.
import org.apache.servicecomb.pack.omega.context.annotations.SagaStart;
@SagaStart(timeout=10)
public boolean transferMoney(String from, String to, int amount) {
transferOut(from, amount);
transferIn(to, amount);
}
Примечание: по умолчанию тайм-аут должен быть явно объявлен для того, чтобы он вступил в силу.
Добавьте аннотацию @Compensable
к дочерней транзакции и укажите соответствующий метод компенсации.
import javax.transaction.Transactional;
import org.apache.servicecomb.pack.omega.transaction.annotations.Compensable;
@Compensable(timeout=5, compensationMethod="cancel")
@Transactional
public boolean transferOut(String from, int amount) {
repo.reduceBalanceByUsername(from, amount);
}
@Transactional
public boolean cancel(String from, int amount) {
repo.addBalanceByUsername(from, amount);
}
Примечание: реализация сервиса использует соответствующие параметры, реализация сервиса и компенсация должны удовлетворять условиям эквивалентности, и рекомендуется использовать Spring @Transactional для обеспечения локальных гарантий транзакций.
Примечание: по умолчанию тайм-аут должен быть явно объявлен для того, чтобы он вступил в силу.
Примечание: если глобальная точка начала транзакции совпадает с дочерней точкой начала транзакции, необходимо одновременно объявить аннотации @SagaStart
и @Compensable
.
Добавьте параметр alpha.cluster.address.
alpha:
cluster:
address: alpha-server.servicecomb.io:8080
Добавьте параметр omega.spec.names.
omega:
spec:
names: saga
Повторите шаги 2 и 3 для дочерних сервисов.
Начиная с pack-0.3.0 вы можете получить доступ к gloableTxId и localTxId информации в функции сервиса или функции отмены.
Начиная с pack-0.7.0 вы можете изменить спецификацию распределённой транзакции с помощью параметра alpha.spec.names, в настоящее время поддерживаются режимы saga-db (по умолчанию), tcc-db, saga-akka. Omega-transport-{dubbo, feign, resttemplate, servicecomb}.
Обратите внимание: когда вы используете компоненты вызова связанных сервисов, пожалуйста, добавьте вышеуказанные компоненты передачи в свой class path. В противном случае соответствующий глобальный идентификатор транзакции не может быть передан в процессе вызова сервиса.
Тогда возникает вопрос: что делать, если контекст транзакции нельзя передать неявно? Например, Service A использует какой-то механизм RPC для вызова Service B, и у вас нет возможности внедрить или извлечь информацию о контексте транзакции. В этом случае вам придётся использовать явный способ передачи контекста транзакции.
С версии 0.5.0 ServiceComb Pack предоставляет два класса для реализации этой функции.
Service A:
@SagaStart
public void foo(BarCommand cmd) {
TransactionContext localTxContext = omegaContext.getTransactionContext();
someRpc.send(cmd, localTxContext);
}
Service B:
public void listen(BarCommand cmd, TransactionContext injectedTxContext) {
bar(cmd, injectedTxContext);
}
@Compensable
public void bar(BarCommand cmd, TransactionContext injectedTxContext) {
...
// TransactionContext localTxContext = omegaContext.getTransactionContext();
}
Следует отметить, что метод bar
получает переданный контекст транзакции, а после входа в bar
из OmegaContext получается локальный контекст транзакции (Omega открыл для вас новую транзакцию). Если Service B также необходимо явно передать контекст транзакции, то следует использовать локальный контекст транзакции.
Service A:
public class BarCommand {}
public class BarCommandWithTxContext
extends BarCommand implements TransactionContextProperties {
// setter getter for globalTxId
// setter getter for localTxId
}
@SagaStart
public void foo(BarCommand cmd) {
BarCommandWithTxContext cmdWithTxContext = new BarCommandWithTxContext(cmd);
cmdWithTxContext.setGlobalTxId(omegaContext.globalTxId());
cmdWithTxContext.setLocalTxId(omegaContext.localTxId());
someRpc.send(cmdWithTxContext);
}
Service B:
public void listen(BarCommandWithTxContext cmdWithTxContext) {
bar(cmdWithTxContext);
}
@Compensable
public void bar(BarCommandWithTxContext cmdWithTxContext) {
...
// TransactionContext localTxContext = omegaContext.getTransactionContext();
}
Как и в предыдущем методе, методы TransactionContextProperties.get{Global, Local}TxId() также возвращают переданный контекст транзакции.
Начиная с pack-0.5.0, атрибут autoClose
был добавлен к @SagaStart
, который используется для управления тем, будет ли автоматически отправляться событие SagaEndedEvent после выполнения метода, помеченного @SagaStart
(по умолчанию — true
). Когда autoClose=false
, вам нужно использовать @SagaEnd
для ручного отправки события SagaEndedEvent
, например:
Service A:
@SagaStart(autoClose=false)
public void foo() {
restTemplate.postForEntity("http://service-b/bar", ...);
}
Service B:
@GetMapping("/bar")
@Compensable
@SagaEnd
public void bar() {
...
}
В соответствующем методе добавьте аннотации TccStart и Participate.
Например, в приложении для перевода денег:
Добавьте аннотацию @TccStart
в глобальную точку транзакции.
import org.apache.servicecomb.pack.omega.context.annotations.TccStart;
@TccStart
public boolean transferMoney(String from, String to, int amount) {
transferOut(from, amount);
transferIn(to, amount);
}
Примечание: текущая версия TCC не поддерживает Timeout.
Добавьте аннотацию @Participate
с указанием соответствующего метода выполнения и метода компенсации в месте попытки подтранзакции.
import javax.transaction.Transactional;
import org.apache.servicecomb.pack.omega.transaction.annotations.Participate;
@Participate(confirmMethod = "confirm", cancelMethod = "cancel")
@Transactional
public void transferOut(String from, int amount) {
// check banalance
}
@Transactional
public void confirm(String from, int amount) {
repo.reduceBalanceByUsername(from, amount);
}
@Transactional
public void cancel(String from, int amount) {
repo.addBalanceByUsername(from, amount);
}
Примечание: методы confirm
и cancel
должны иметь тот же список параметров, что и метод @Participate
, и они должны быть идемпотентными. Мы настоятельно рекомендуем использовать Spring @Transactional
для обеспечения согласованности локальных транзакций.
Примечание: если глобальная точка транзакции и точка подтранзакции совпадают, необходимо одновременно объявить аннотации @TccStart
и @Participate
.
Добавьте параметр alpha.cluster.address.
alpha:
cluster:
address: alpha-server.servicecomb.io:8080
Добавьте параметр omega.spec.names.
omega:
spec:
names: tcc
Повторите шаги 2–4 для службы-получателя.
Начиная с версии pack-0.3.0, вы можете получить информацию gloableTxId и localTxId в функции сервиса или функции отмены, обратившись к OmegaContext. | | 2.3.12.RELEASE | 2.2.10.RELEASE | | :--: |:--:| --:| | 2.1.x.RELEASE | 2.1.1.RELEASE | | 2.0.x.RELEASE | 2.0.3.RELEASE |
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
注意: Если вы в запуске Alpha при помощи командной строки указали параметр spring.application.name
, то вам необходимо в Omega указать этот параметр как alpha.cluster.serviceId
.
Запуск alpha
Во время выполнения добавьте параметр spring.cloud.zookeeper.enabled=true
.
java -jar alpha-server-${saga_version}-exec.jar \
--spring.datasource.url=jdbc:postgresql://${host_address}:5432/saga?useSSL=false \
--spring.datasource.username=saga \
--spring.datasource.password=saga \
--spring.cloud.zookeeper.enabled=true \
--spring.cloud.zookeeper.connectString=${zookeeper_host}:${zookeeper_port} \
--spring.profiles.active=prd
Примечание: ${zookeeper_host}
— это адрес zookeeper, а ${zookeeper_port}
— порт zookeeper.
Примечание: для получения дополнительной информации о параметрах Zookeeper обратитесь к документации Spring Cloud Zookeeper 2.x или Spring Cloud Zookeeper 1.x.
Проверка успешной регистрации
Посетите экземпляр Zookeeper и в znode /services/servicecomb-alapha-server
проверьте znode регистрации. В зарегистрированном znode должно быть следующее значение:
{
"name": "servicecomb-alpha-server",
"id": "9b2223ae-50e6-49a6-9f3b-87a1ff06a016",
"address": "arch-office",
"port": 8090,
"sslPort": null,
"payload": {
"@class": "org.springframework.cloud.zookeeper.discovery.ZookeeperInstance",
"id": "servicecomb-alpha-server-1",
"name": "servicecomb-alpha-server",
"metadata": {
"servicecomb-alpha-server": "arch-office:8080"
}
},
"registrationTimeUTC": 1558000134185,
"serviceType": "DYNAMIC",
"uriSpec": {
"parts": [
{
"value": "scheme",
"variable": true
},
{
"value": "://",
"variable": false
},
{
"value": "address",
"variable": true
},
{
"value": ":",
"variable": false
},
{
"value": "port",
"variable": true
}
]
}
}
Примечание: по умолчанию зарегистрированное имя службы — servicecomb-alpha-server
. Если вам нужно настроить имя службы, вы можете сделать это во время запуска Alpha с помощью параметра командной строки spring.application.name
.
Настройка omega
Включите зависимость пакета omega-spring-cloud-zookeeper-starter
в проект.
<dependency>
<groupId>org.apache.servicecomb.pack</groupId>
<artifactId>omega-spring-cloud-zookeeper-starter</artifactId>
<version>${pack.version}</version>
</dependency>
В файле application.yaml
добавьте следующие настройки:
spring:
cloud:
zookeeper:
enabled: true
connectString: 127.0.0.1:2181
alpha:
cluster:
register:
type: zookeeper
spring.cloud.zookeeper.connectString
— настройка адреса регистрационного центра Zookeeper. Дополнительные сведения о конфигурации клиента zookeeper см. в документации Spring Cloud Zookeeper 2.x и Spring Cloud Zookeeper 1.x.
alpha.cluster.register.type=zookeeper
— настройка способа получения Omega от Alpha через центр регистрации Zookeeper.
Совместимость со Spring Boot
Если ваш проект использует версию Spring Boot, отличную от версии 2.3.X, пожалуйста, обратитесь к этому списку для добавления совместимой версии spring-cloud-starter-zookeeper-discovery.
spring boot | spring-cloud-starter-zookeeper-discovery |
---|---|
Не 2.3.Х | версия spring-cloud-starter-zookeeper-discovery, соответствующая вашей версии Spring Boot |
2.3.12.RELEASE | 2.2.5.RELEASE |
2.1.x.RELEASE | 2.1.1.RELEASE |
1.5.17.RELEASE | 1.2.2.RELEASE |
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
Примечание: Если вы при запуске Alpha через командную строку указали имя сервиса с помощью параметра spring.application.name
, то в Omega вам нужно будет указать это же имя сервиса через параметр alpha.cluster.serviceId
.
Запустите alpha:
Во время выполнения добавьте параметр nacos.client.enabled=true
.
java -jar alpha-server-${saga_version}-exec.jar \
--spring.datasource.url=jdbc:postgresql://${host_address}:5432/saga?useSSL=false \
--spring.datasource.username=saga \
--spring.datasource.password=saga \
--spring.cloud.nacos.discovery.enabled=true \
--spring.cloud.nacos.discovery.serverAddr=${nacos_host}:${nacos_port} \
--nacos.client.enabled=true \
--spring.profiles.active=prd
Примечание: ${nacos_host}
— это адрес nacos, ${nacos_port}
— порт nacos.
Примечание: Для получения дополнительной информации о параметрах Nacos обратитесь к Spring Cloud Nacos Discovery.
Проверьте успешность регистрации:
Посетите экземпляр Nacos и используйте OpenAPI для запроса curl -X GET 'http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=servicecomb-alpha-server'
. Вы увидите следующую информацию о регистрации сервисов. В разделе metadata можно найти адрес gRPC, который уже зарегистрирован.
{
"metadata": {},
"dom": "servicecomb-alpha-server",
"cacheMillis": 3000,
"useSpecifiedURL": false,
"hosts": [
{
"valid": true,
"marked": false,
"metadata": {
"preserved.register.source": "SPRING_CLOUD",
"servicecomb-alpha-server": "192.168.2.28:8080"
},
"instanceId": "192.168.2.28#8090#DEFAULT#DEFAULT_GROUP@@servicecomb-alpha-server",
"port": 8090,
"healthy": true,
"ip": "192.168.2.28",
"clusterName": "DEFAULT",
"weight": 1,
"ephemeral": true,
"serviceName": "servicecomb-alpha-server",
"enabled": true
}
],
"name": "DEFAULT_GROUP@@servicecomb-alpha-server",
"checksum": "d9e8deefd1c4f198980f4443d7c1b1fd",
"lastRefTime": 1562567653565,
"env": "",
"clusters": ""
}
Примечание: По умолчанию регистрируется сервис с именем servicecomb-alpha-server
. Если вам необходимо настроить другое имя сервиса, вы можете сделать это во время запуска Alpha с помощью командной строки spring.application.name
.
Настройте omega:
Включите зависимость пакета omega-spring-cloud-nacos-starter
в проект.
<dependency>
<groupId>org.apache.servicecomb.pack</groupId>
<artifactId>omega-spring-cloud-nacos-starter</artifactId>
<version>${pack.version}</version>
</dependency>
В файле application.yaml
добавьте следующие настройки:
spring:
cloud:
nacos:
discovery:
enabled: true
serverAddr: 127.0.0.1:8848
alpha:
cluster:
register:
type: nacos
spring.cloud.nacos.discovery.serverAddr
— настройка адреса центра регистрации Nacos. Для получения дополнительных сведений о параметрах Nacos см. Spring Cloud Nacos Discovery
alpha.cluster.register.type=nacos
— настройка способа получения Omega от Alpha через центр регистрации Nacos.
Совместимость со Spring Boot:
Если ваш проект использует версию Spring Boot, отличную от версии 2.3.X, пожалуйста, обратитесь к этому списку для добавления совместимой версии spring-cloud-starter-alibaba-nacos-discovery.
| spring boot | spring-cloud-starter-alibaba-nacos-discovery | ----------------| ------------- | ------------------------------------- | | 2.3.12.RELEASE | 2.2.6.RELEASE | | 2.1.x.RELEASE | 0.2.2.RELEASE | | 1.5.17.RELEASE | 0.1.2.RELEASE | ``` spring-cloud-starter-alibaba-nacos-discovery 2.2.6.RELEASE
注意: Если вы при запуске Alpha через командную строку с помощью параметра spring.application.name
задали имя сервиса, то в Omega вам нужно указать это имя сервиса через параметр alpha.cluster.serviceId
.
Alpha может обеспечить высокую доступность путём развёртывания нескольких экземпляров. Для этого включите поддержку кластера, установив параметр alpha.cluster.master.enabled=true
.
Чтобы включить функцию JNI вызова Socket Transport в Alpha, установите параметр alpha.feature.nativetransport=true
. По сравнению с транспортом на основе NIO, эти JNI передачи добавляют функции, специфичные для конкретной платформы, производят меньше мусора и в целом повышают производительность.
Спецификация распределённого конечного автомата Saga-Akka
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )