El viaje de transacciones distribuidas a partir de la instalación de Seata
- introducir
- Instalar servidor de Seat
- Integrar Seata en el proyecto Spring Boot
- Resumir
- Referencias
introducir
¿Qué es Seata?
En el desarrollo de aplicaciones modernas, los sistemas distribuidos se utilizan cada vez más. Sin embargo, a medida que aumenta la complejidad del sistema, se vuelve cada vez más difícil manejar transacciones distribuidas. Este es el trasfondo en el que surge Seata. Seata (Simple Extensible Autonomous Transaction Architecture) es una solución de transacciones distribuidas de código abierto diseñada para resolver problemas de consistencia y coordinación de transacciones en sistemas distribuidos.
En las aplicaciones monolíticas tradicionales, las bases de datos relacionales suelen utilizarse para gestionar transacciones y garantizar la coherencia de los datos. Pero en un sistema distribuido, la gestión de transacciones se vuelve complicada porque están involucrados múltiples servicios independientes. El requisito de una transacción distribuida es que todos los servicios involucrados se confirmen con éxito o se reviertan para mantener la consistencia de los datos.
Seata proporciona dos modos de transacción principales:
-
Modo AT (Modo de compensación automática): En el modo AT, Seata compensará automáticamente las transacciones sin escribir manualmente la lógica de compensación. Seata organizará todas las operaciones de la transacción en una transacción global, luego ejecutará la operación de prueba de cada sucursal y realizará la operación de compensación correspondiente cuando ocurra una excepción.
-
Modo TCC (modo de compromiso de dos fases): el modo TCC requiere que los desarrolladores escriban manualmente la lógica de las tres fases de Probar, Confirmar y Cancelar. En el modo TCC, Seata es responsable de coordinar el compromiso y la reversión de las transacciones globales, mientras que los desarrolladores implementan las operaciones de prueba, confirmación y cancelación de cada sucursal.
Seata también proporciona soporte de almacenamiento y registro escalable, lo que lo hace adecuado para varios escenarios.
En general, Seata es una poderosa solución de transacciones distribuidas que puede ayudar a los desarrolladores a resolver problemas de transacciones distribuidas y garantizar la consistencia y confiabilidad de los datos en sistemas distribuidos. Al integrar Seata, los desarrolladores pueden construir más fácilmente aplicaciones distribuidas complejas y mejorar la estabilidad y el rendimiento del sistema.
Instalar servidor de Seat
Descarga la versión de Seata Server
Puede descargar la última versión de Seata Server desde el sitio web oficial de Seata y descomprimirlo en un directorio específico; hay versiones fuente y binaria, aquí elegimos instalar el archivo binario para descargar. Mi versión es 1.7.0 (2023-07-11, versión recomendada)
Configurar Seata
descomprimir archivos
El archivo descargado es un archivo zip, y después de la descompresión, será la carpeta de arriba. El nombre de carpeta predeterminado es seata.
Configurar el archivo yml de Seata
Ingrese seata/conf
al directorio, hay dos archivos de configuración aquí, necesitamos application.yml
modificar un nombre a voluntad y luego application.example.yml
modificarlo application.yml
como el archivo de configuración principal.
Modifique application.yml
el archivo, aquí uso nacos como centro de registro, por lo que los lugares que deben modificarse son:
- asiento:config:tipo
- seata:registro:tipo
- tienda: modo
- tienda:sesión:modo
- tienda: bloqueo: modo
- store:db La configuración de la base de datos se modifica a su propia
Archivo de configuración:
server:
port: 7091
spring:
application:
name: seata-server
logging:
config: classpath:logback-spring.xml
file:
path: ${
user.home}/logs/seata
extend:
logstash-appender:
destination: 127.0.0.1:4560
kafka-appender:
bootstrap-servers: 127.0.0.1:9092
topic: logback_to_logstash
# 这里是主要的配置文件
seata:
config:
# support: nacos 、 consul 、 apollo 、 zk 、 etcd3
type: nacos
nacos:
server-addr: 127.0.0.1:8848
# 如果在nacos上添加了命名空间,则配置命令空间ID
namespace:
# 配置分组
group: SEATA_GROUP
username:
password:
context-path:
##if use MSE Nacos with auth, mutex with username/password attribute
#access-key:
#secret-key:
data-id: seataServer.properties
registry:
# support: nacos 、 eureka 、 redis 、 zk 、 consul 、 etcd3 、 sofa
type: nacos
preferred-networks: 30.240.*
nacos:
application: seata-server
server-addr: 127.0.0.1:8848
group: SEATA_GROUP
namespace:
cluster: default
username:
password:
context-path:
##if use MSE Nacos with auth, mutex with username/password attribute
#access-key:
#secret-key:
server:
service-port: 8091 #If not configured, the default is '${server.port} + 1000'
max-commit-retry-timeout: -1
max-rollback-retry-timeout: -1
rollback-retry-timeout-unlock-enable: false
enable-check-auth: true
enable-parallel-request-handle: true
retry-dead-threshold: 130000
xaer-nota-retry-timeout: 60000
enableParallelRequestHandle: true
recovery:
committing-retry-period: 1000
async-committing-retry-period: 1000
rollbacking-retry-period: 1000
timeout-retry-period: 1000
undo:
log-save-days: 7
log-delete-period: 86400000
session:
branch-async-queue-size: 5000 #branch async remove queue size
enable-branch-async-remove: false #enable to asynchronous remove branchSession
store:
# support: file 、 db 、 redis
mode: db
session:
mode: db
lock:
mode: db
db:
datasource: druid
db-type: mysql
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true
user: mysql
password: mysql
min-conn: 10
max-conn: 100
global-table: global_table
branch-table: branch_table
lock-table: lock_table
distributed-lock-table: distributed_lock
query-limit: 1000
max-wait: 5000
metrics:
enabled: false
registry-type: compact
exporter-list: prometheus
exporter-prometheus-port: 9898
transport:
rpc-tc-request-timeout: 15000
enable-tc-server-batch-send-response: false
shutdown:
wait: 3
thread-factory:
boss-thread-prefix: NettyBoss
worker-thread-prefix: NettyServerNIOWorker
boss-thread-size: 1
Cargue el archivo de configuración config.txt a nacos
Modificar el archivo config.txt
config.txt
El archivo está en seata/script/config-center
el directorio, los lugares que necesitamos modificar son:
- tienda.modo=db
- store.lock.mode=db
- store.session.mode=db
- La configuración de la base de datos store.db se modifica por sí misma, que es la misma que en el archivo yml anterior
Cargalo en nacos
Introduzca seata/script/config-center/nacos
el directorio para ejecutar nacos-config.sh
el archivo.
sh nacos-config.sh -h 121.37.228.169 -p 8848 -g SEATA_GROUP -t 0af6e97b-a684-4647-b696-7c6d42aecce7 -u nacos -w nacos
- -h: dirección IP de Nacos
- -p: número de puerto Nacos
- -g: nombre del grupo del grupo
- -t: ID de espacio de nombres, si no es público de forma predeterminada
- -u: nombre de usuario
- -w: contraseña
Una vez completada la ejecución, inicie sesión en nuestra gestión de configuración de Nacos para ver los datos cargados:
Iniciar el servicio Seata
Comienzo normal
Ingrese seata/bin
al directorio y ejecute el comando:
sh seata-server.sh
Aquí puedo encontrar una situación anormal cuando lo inicio. A continuación, he enumerado algunas dificultades que encontré al iniciarlo. puede moverse a启动时遇到的坑
Ver registro de inicio
Mi sistema Mac está abierto para abrir archivos de registro. Otros sistemas necesitan ejecutar comandos de acuerdo con el sistema, o ingresar directamente al seata/logs
directorio para ver start.out
los archivos.
open /Users/ddz/Downloads/seata/logs/start.out
Puede ver la dirección de salida del registro que indica que el inicio se realizó correctamente.
Abre la página de la consola
En la página de la consola , la contraseña de cuenta predeterminada es seata/seata.
Hoyo encontrado al inicio
Aquí hay algunas dificultades que encontré al implementar Seata, y puede haber diferencias entre ellas solo como referencia.
No se puede resolver el valor de ${console.user.username}
Información de excepción : no se pudo resolver el marcador de posición 'console.user.username' en el valor "${console.user.username}"
Solución : debe copiar toda la información de configuración en el archivo yml que se modificó previamente con otro nombre console
al actual application.yml
uno Aquí se establece la contraseña de la cuenta para nuestra página de consola de inicio de sesión.
No se puede analizar el valor de ${seata.security.secretKey}
Información de excepción : no se pudo resolver el marcador de posición 'seata.security.secretKey' en el valor "${seata.security.secretKey}"
Solución : debe copiar toda la información de configuración en el archivo yml que se modificó previamente con otro nombre seata.security
al actual application.yml
uno
problema de conexion a la base de datos
Información de excepción : com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: falla del enlace de comunicaciones
En versiones anteriores a MySQL5.7, la seguridad es baja y cualquier usuario puede conectarse a la base de datos, por lo que la versión oficial 5.7 ha aumentado la protección de la privacidad. Y se adopta el valor predeterminado useSSL = true para evitar la modificación aleatoria de la base de datos.En la versión 8.0, aún se conserva SSL y el valor predeterminado es true.
Solución : agregue después de la URL de configuración de la base de datos &useSSL=false
; debe verificar el archivo de configuración yml y la lista de configuración en Nacos store.db.url
.
Integrar Seata en el proyecto Spring Boot
Anteriormente presentamos cómo instalar el servidor seata localmente y luego presentamos la integración de seata en nuestro proyecto Spring Boot; aquí solo uso una demostración para presentarlo, que puede implementarse de acuerdo con su propia lógica comercial.
ambiente de trabajo
- MySQL 5.7.28
- Experto 3.5.4
- JDK 1.8
- Mibot 3.4.1
- dinámico 3.4.1
nube, arranque, entorno alibaba
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
<spring-cloud-alibaba.version>2.2.6.RELEASE</spring-cloud-alibaba.version>
agregar dependencias
<!-- MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- Mybatis -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<!-- 多数据源 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<!-- Seata分布式事务 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
configuración yml
server:
port: 7001
spring:
application:
name: ddz-user
cloud:
nacos:
discovery:
# 服务分组
group: ddz
server-addr: 121.37.228.111:8848
# 必须填命名空间的ID
# namespace: 9ebef975-dcc0-4430-9c63-1c62d8a86d82
datasource:
dynamic:
# 开启seata分布式事务
seata: true
strict: false
primary: master
datasource:
master:
url: jdbc:mysql://121.37.228.111:3306/ddz?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true
username: ddz
password: ddz2023
local:
url: jdbc:mysql://127.0.0.1:3306/ddz?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true
username: root
password: ddz2023
# MyBatis Plus配置
mybatis-plus:
# 搜索指定包别名
typeAliasesPackage: com.ddz.**.entity
# 配置mapper的扫描,找到所有的mapper.xml映射文件
mapperLocations: classpath*:mapper/**/*.xml
global-config:
db-config:
id-type: auto
configuration:
# 开启驼峰,开启后,只要数据库字段和对象属性名字母相同,无论中间加多少下划线都可以识别
map-underscore-to-camel-case: true
# Seata 配置
seata:
application-id: seata-server
# 是否启用数据源bean的自动代理
enable-auto-data-source-proxy: false
tx-service-group: default_tx_group # 必须和服务器配置一样
registry:
type: nacos
nacos:
# Nacos 服务地址
server-addr: 121.37.228.111:8848
group: SEATA_GROUP
# namespace: 9ebef975-dcc0-4430-9c63-1c62d8a86d82
application: seata-server # 必须和服务器配置一样
# username:
# password:
cluster: default
config:
type: nacos
nacos:
server-addr: 121.37.228.111:8848
group: SEATA_GROUP
# namespace: 9ebef975-dcc0-4430-9c63-1c62d8a86d82
service:
vgroup-mapping:
default_tx_group: default # 必须和服务器配置一样
disable-global-transaction: false
client:
rm:
# 是否上报成功状态
report-success-enable: true
# 重试次数
report-retry-count: 5
Integrar Seata en el código empresarial
Creamos dos mapper
clases basadas en dos fuentes de datos y luego controller
las probamos; omito la capa empresarial por la conveniencia de probar aquí.
Use @GlobalTransactional
anotaciones para administrar transacciones globales
Demuestra el modo AT (compensación automática) y el modo TCC (compromiso de dos fases)
Utilice el modo AT (compensación automática)
En el modo AT, Seata compensará automáticamente las transacciones sin escribir manualmente la lógica de compensación. Primero, demostremos un escenario de transferencia simple, transfiriendo fondos de una cuenta a otra y asegurando la consistencia de la transacción.
- Agregue la anotación @GlobalTransactional
Agregue la anotación @GlobalTransactional al método del servicio de transferencia para marcar la transacción global:
@Service
public class TransferService {
@GlobalTransactional
public void transfer(String fromAccount, String toAccount, double amount) {
// 扣除转出账户金额
deductAmount(fromAccount, amount);
// 增加转入账户金额
addAmount(toAccount, amount);
}
// 实现扣除金额逻辑
// ...
// 实现增加金额逻辑
// ...
}
- Pruebe el modo AT
Escriba casos de prueba para verificar la gestión de transacciones en modo AT:
@RunWith(SpringRunner.class)
@SpringBootTest
public class TransferServiceTest {
@Autowired
private TransferService transferService;
@Test
public void testTransfer() {
// 假设从账户 A 转账 100 到账户 B
transferService.transfer("accountA", "accountB", 100.0);
}
}
Ejecute el caso de prueba para observar si la transferencia es exitosa y verifique el registro para confirmar si Seata compensó automáticamente la transacción.
Usar el modo TCC (compromiso de dos fases)
En el modo TCC, necesitamos escribir manualmente la lógica de las tres fases de Probar, Confirmar y Cancelar para asegurar la correcta ejecución de la transacción. Demostremos un escenario simple de creación de pedidos, que incluye tres etapas: realizar un pedido, deducir el inventario y crear un pedido.
- Implemente la interfaz TCC
Cree una interfaz TCC e implemente la lógica de las tres etapas de Probar, Confirmar y Cancelar:
public interface OrderTccService {
@GlobalTransactional
boolean createOrder(OrderDTO orderDTO);
@TwoPhaseBusinessAction(name = "orderTccService", commitMethod = "confirmOrder", rollbackMethod = "cancelOrder")
boolean tryCreateOrder(OrderDTO orderDTO);
boolean confirmOrder(OrderDTO orderDTO);
boolean cancelOrder(OrderDTO orderDTO);
}
- Implementar lógica TCC
Escribir lógica TCC en la clase de implementación:
@Service
public class OrderTccServiceImpl implements OrderTccService {
@Override
public boolean tryCreateOrder(OrderDTO orderDTO) {
// 预留库存逻辑
// ...
return true;
}
@Override
public boolean confirmOrder(OrderDTO orderDTO) {
// 确认创建订单逻辑
// ...
return true;
}
@Override
public boolean cancelOrder(OrderDTO orderDTO) {
// 取消创建订单逻辑
// ...
return true;
}
}
- Pruebe el modo TCC
Escriba casos de prueba para verificar la gestión de transacciones del modo TCC:
@RunWith(SpringRunner.class)
@SpringBootTest
public class OrderTccServiceTest {
@Autowired
private OrderTccService orderTccService;
@Test
public void testCreateOrder() {
// 创建一个订单
OrderDTO orderDTO = new OrderDTO();
// 设置订单信息
// ...
orderTccService.createOrder(orderDTO);
}
}
Ejecute el caso de prueba para observar si la orden se crea correctamente y verifique el registro para confirmar si las fases Try, Confirm y Cancel del modo TCC se ejecutan correctamente.
Integrar el foso que pisó Seata
Aquí hay algunas dificultades que encontré durante el proceso de integración, y puede haber diferencias entre ellas solo como referencia.
La tabla 'ddz.undo_log' no existe
Información de excepción : proceso de error de confirmación de connectionProxy: la tabla 'ddz.undo_log' no existe.
Solución : elimine la tabla de registro que necesita Seata en la fuente de datos; agregue una nueva undo_log
tabla en cada fuente de datos.
CREATE TABLE `undo_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`branch_id` bigint(20) NOT NULL,
`xid` varchar(100) NOT NULL,
`context` varchar(128) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int(11) NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
`ext` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
no se encontró ningún servicio disponible 'null', asegúrese de que la configuración del registro sea correcta
Información de excepción : la razón de esto es que no cargamos Seata config.txt
en nacos.
Solución : Ejecute el comando para cargar la configuración en el centro de configuración de Nacos. Consulte lo anterior:把配置文件config.txt加载到nacos上
La transacción distribuida no tiene efecto
Motivo : las múltiples fuentes de datos que utilizamos dynamic
no habilitan Seata
las transacciones distribuidas de forma predeterminada.
Solucióndynamic
: agregue la configuración en el archivo de configuración yml seata: true
para habilitar las transacciones distribuidas.
la fuente de datos dinámica no puede encontrar la fuente de datos principal
Motivo : Este es un error en la información de configuración de la fuente de datos. El motivo de esta excepción es que soy demasiado descuidado para escribir la conexión de la base de datos (url) incorrectamente.
Solución : vuelva a verificar datasource
la configuración de las siguientes fuentes de datos.
Fallo en el enlace de comunicaciones
Razón : la mayoría de las razones aquí son que MySQL necesita especificar si se debe realizar una conexión SSL, y la conexión SSL está habilitada de manera predeterminada.
Solución : simplemente agréguelo después de la URL de configuración de la conexión a la base de datos &useSSL=false
.
Resumir
A medida que los sistemas distribuidos continúan evolucionando, también lo hará el campo de las transacciones distribuidas. En el futuro, podemos explorar más modelos y soluciones de transacciones distribuidas para satisfacer las necesidades de diferentes escenarios comerciales. Al mismo tiempo, Seata, como proyecto activo de código abierto, seguirá introduciendo nuevas funciones y mejoras. Podemos estar atentos a las actualizaciones de la comunidad de Seata y aportar nuestra propia fuerza.
Además, además de Seata, existen otras soluciones de transacciones distribuidas, como TCC-Transaction
, SAGA
, , HSTC
etc. Estas soluciones también merecen nuestro estudio y exploración en profundidad. De acuerdo con diferentes escenarios comerciales, podemos elegir la solución más adecuada para resolver el problema de transacciones distribuidas.
Referencias
Documentación Oficial Nacos Documentación
Oficial Seata Documentación
Oficial Spring Boot