首页 / 资讯中心 / 文章详情

Spring Cloud Alibaba Seata-server 1.2安装配置与启动实战指南

Spring Cloud Alibaba Seata-server 1.2安装配置与启动实战指南 ★ FEATURED ARTICLE
你是不是也遇到过这种情况订单服务和库存服务本地都调通了结果一旦真正下单订单表里多了一条记录库存却扣减失败或者反过来库存扣了订单没生成。问题不在业务代码而是多个服务之间没有统一的分布式事务协调机制。Spring Cloud Alibaba生态里承担这个职责的是Seata而Seata-server就是它的大脑TC所有事务分支的提交、回滚决策都要经过它。这篇就专门讲Spring Cloud Alibaba项目里Seata-server 1.2版本从下载、配置到启动的完整过程以及我在实际环境里踩过的坑。适合正在搭分布式事务基础环境、第一次接触Seata或者从1.0往1.2迁移的读者参考。1. 先搞清楚Seata-server承载什么职责再动手装也不迟1.1 分布式事务里的TC、TM、RM角色划分Seata的事务模型里分三个角色很多第一次接触的人容易绕晕。TCTransaction Coordinator就是Seata-server本身它负责维护全局事务的状态协调分支事务的提交和回滚TMTransaction Manager在业务发起方负责开启全局事务、提交或回滚全局事务RMResource Manager在各个参与服务里管理每个分支事务的资源比如订单服务里的数据库操作就是一个RM。为了方便理解可以把TC想象成一个调度中心TM打电话告诉它“我要开始一个大事务了”TC就创建一个全局事务IDXID各个RM执行完自己的本地SQL后向TC登记“我这边成功了等你发落”等所有RM都报到了TM再告诉TC“可以提交了”TC就通知所有RM提交如果有任何一个RM报错TC就通知所有已经登记过的RM回滚。这里的关键点是每个RM只是“预备提交”真正的一锤定音者是TC。1.2 1.2版本在Spring Cloud Alibaba生态里的定位Seata版本迭代节奏比较快1.2版本在Spring Cloud Alibaba的搭配里很常见。这个版本的特点是用Registry和Config两层模型服务端和客户端都通过registry.conf和file.conf两个文件来定义注册方式、配置来源和存储方式不像后续版本那样统一收敛到单一配置文件里。所以网上很多1.4、2.0版本的教程直接照搬过来往往跑不通因为配置结构变了。1.2版本支持nacos、eureka、consul等注册中心也支持file、db两种事务存储模式。本地调试建议先用file模式把流程跑通再切db模式用于生产。我见过不少人一上来就强行配Nacos加db模式结果配置文件里一个字段写错启动日志刷一堆naming exception反而不知道问题出在Seata还是Nacos。所以这篇从最稳的组合开始Nacos做注册中心文件配置为主存储先用file模式跑通后面再讲切db。2. 动手前的准备版本搭配和资源确认2.1 JDK、数据库、Nacos版本的搭配参考Seata-server 1.2是Java应用建议JDK 1.8这个版本在JDK 8下运行最稳不需要上11或17。Nacos建议用1.x系列比如1.3.2或者1.4.2都行因为1.2版本的Seata内置的Nacos客户端兼容性只到Nacos 1.x直接配Nacos 2.x会出现服务注册成功但客户端发现不了实例、事务一直超时的诡异问题。我遇到过一位同事把Nacos升到2.2.0之后Seata-server明明已经注册上去了业务系统却总是报Could not found global services最后降回1.4.2才恢复正常。JDBC驱动要单独强调一下如果数据库是MySQL 5.7驱动类用com.mysql.jdbc.Driver如果是MySQL 8.0及以上驱动类必须用com.mysql.cj.jdbc.Driver而且JDBC URL里建议加上serverTimezoneAsia/Shanghai和useSSLfalse不然启动时可能出现时区异常或SSL握手报错。2.2 获取seata-server-1.2.0安装包的方式安装包可以从Seata官方Release页面下载文件名一般是seata-server-1.2.0.zip大概几十MB包含bin、conf、lib三个核心目录。如果从官方下载比较慢也可以去Maven中央仓库找io.seata:seata-server对应的发行包用Maven下载的方式拉下来本质是同一个发行物。不推荐随便在网上找第三方打包的“精简版”或者“一键集成包”这类包常常改过默认配置出了问题你根本不知道它动了哪里。下载完成后用unzip seata-server-1.2.0.zip解压到指定目录例如/opt/seata。解压之后别急着启动先看看目录结构bin启动脚本Linux环境用seata-server.shWindows环境用seata-server.bat。conf核心配置目录里面一定要有registry.conf和file.conf这两个文件是1.2版本的关键。libSeata依赖的jar包包括传输协议、配置解析等如果你要用db模式提前确认这里有没有对应的数据库驱动。2.3 解压后的目录结构conf和lib最值得先看进入解压目录后我习惯先检查lib下有没有mysql-connector-java相关jar。有些发行包自带驱动有些没有。如果没有就需要自行下载对应版本的mysql-connector-java放到lib目录下不然后面把store.mode切换成db时会一直报找不到驱动类。这个问题很隐蔽因为启动日志里不会直接说“没有驱动”而是报ClassNotFoundException你可能会往配置文件方向排查很久。然后再看registry.conf这个文件控制两个东西注册中心和配置中心。1.2版本的Seata允许注册中心用Nacos、配置中心也用Nacos也可以注册中心用Nacos、配置中心继续走本地文件。我建议刚开始调试时配置中心保持file模式减少一个变量业务系统正常连接之后再考虑把配置中心也切到Nacos做统一配置管理。3. 初始化数据库脚本Seata自己的三张表不能少3.1 为什么需要global_table、branch_table、lock_table如果你打算用db模式存储事务状态数据库里必须建三张表global_table记录全局事务信息branch_table记录每个分支事务信息lock_table记录全局锁信息。三张表的用途要理清global_table里会有xid、transaction_id、status、application_id这些字段一个全局事务在这里对应一行branch_table里以branch_id为维度记录每个RM注册过来的分支事务状态lock_table负责全局锁用来避免多个全局事务并发操作同一行数据时产生冲突。如果只做本地调试用file模式可以不建这三张表因为事务数据会落成文件。但只要你把store.mode改成db这三张表缺一张都会出现诡异的运行时错误比如分支事务注册失败、回滚找不到全局事务这类问题。所以我建议即使现在用file模式也顺手把表建好省得后面切换的时候手忙脚乱。3.2 脚本执行步骤和表字段简单解读SQL脚本可以从Seata源码里script/server/db/目录下找也可以从官方文档对应版本页面复制。不同版本的表结构有差异务必找1.2版本对应的脚本不要拿1.4或2.x的脚本直接执行表字段可能会和你用的Seata版本对不上。在我的环境里我是先建了一个独立的数据库seata然后执行脚本。连接命令大概是这样的CREATE DATABASE IF NOT EXISTS seata DEFAULT CHARACTER SET utf8mb4; USE seata; -- 这里执行从官方复制下来的 mysql.sql 脚本执行完之后可以用下面这句快速确认SHOW TABLES FROM seata; -- 期望结果branch_table, global_table, lock_tableglobal_table里的status字段很关键不同数字代表不同事务状态比如0表示开始1表示全局提交中2表示全局回滚中3表示全局提交完成4表示全局回滚完成等。排查事务卡住的时候直接看这个字段就知道全局事务走到哪一步了。lock_table里的pk字段是加锁行的主键值配合resource_id和table_name可以定位到具体是哪一行数据被锁住了。如果只想快速验证也可以先不管这三张表用file模式把server跑起来确认业务能正常通信再回来建表和切db模式。但千万别在生产环境用file模式跑太久file模式下Seata重启后事务文件可能存在历史残留恢复逻辑没有db模式清晰。4. 修改配置registry.conf与file.conf是1.2版本的灵魂4.1 registry.conf把seata-server注册到Nacos1.2版本的registry.conf看起来有些老旧但逻辑其实很清晰。服务端启动时它先读registry段决定怎么把自己的地址暴露给客户端再读config段决定自己的配置从哪里读取。我们这次用Nacos做注册中心配置中心先保持file也就是下面这个样子registry { type nacos nacos { application seata-server serverAddr 127.0.0.1:8848 namespace cluster default group SEATA_GROUP } } config { type file }有几个点要特别注意。namespace如果为空表示使用Nacos的public命名空间如果你在Nacos里创建了专门的命名空间这里要填命名空间ID不是填名称。cluster字段是Seata的事务分组概念默认default就好客户端配置里的分组成员必须和这里对应否则客户端在Nacos上找到了Seata-server却找不到对应集群的实例事务还是会失败。group表示Nacos上的配置分组保持SEATA_GROUP是通用约定客户端和服务端要一致。如果Nacos没有开启鉴权不需要额外配置username和password如果开启了鉴权还要在nacos段里追加username和password字段。鉴权配置建议先不要开本地调试把流程打通了再考虑。4.2 file.confstore模式改为db重点参数逐个说file.conf里面内容很多但真正需要动手改的核心就两块service和store。service段里有事务分组映射比如这一行service { vgroupMapping.my_test_tx_group default default.grouplist 127.0.0.1:8090 enableDegrade false disableGlobalTransaction false }vgroupMapping.my_test_tx_group的意思是你给事务分组起了一个名字my_test_tx_group它映射到Seata-server集群default。这个名字可以自定义但必须和业务系统里配置的tx-service-group保持一致否则客户端拿到全局事务ID后不知道应该找哪个Seata-server集群来完成后续协调。default.grouplist是文件直连模式下的服务端地址列表如果你不用注册中心就靠这个字段找到Seata-server如果用了Nacos注册中心那么这个字段的作用会被注册中心替代但保持它填写正确没有坏处。store段这样改store { mode db db { driverClassName com.mysql.cj.jdbc.Driver url jdbc:mysql://127.0.0.1:3306/seata?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai user root password 你的数据库密码 minConn 5 maxConn 20 globalTable global_table branchTable branch_table lockTable lock_table queryLimit 100 maxWait 5000 } }mode从file改成db之后Seata-server启动时就会连接数据库把事务数据落库。driverClassName要根据MySQL版本来选MySQL 8.0用com.mysql.cj.jdbc.DriverMySQL 5.7用com.mysql.jdbc.Driver选错会直接启动失败。url里的seata是数据库名要和前面建表时保持一致。minConn和maxConn是连接池参数本地调试不需要调太大maxConn20足够但要注意如果业务并发高峰很高maxConn太小会导致事务状态入库排队出现全局事务超时。4.3 配置里几个默认值的“坑位”说明第一处store段的mode如果在file和db之间切换不要只改这里还要检查file.conf里的store.file.dir是否指向了一个可写目录。我曾经把mode改成db之后启动日志还提示file_store相关异常反复看才发现store段下面还留着几行不必要的file配置虽然不至于报错但看着很迷惑。第二处default.grouplist里的端口号不一定是8090。Seata服务端默认监听端口在不同安装包和文档里可能显示8090或者8091这取决于版本和启动参数。最好的办法是不要凭记忆猜端口而是启动服务后看日志里实际绑定的端口再把客户端这边的grouplist填成一致。我在排错时见过很多次服务端正常、客户端也正常就是两边端口不一致导致事务一直协调不上。第三处registry.conf里namespace字段如果是空字符串不要画蛇添足改成public。在Nacos 1.x版本里public命名空间对应的值就是空字符串写了public反而可能造成服务注册到了意外的地方。如果你在Nacos控制台看到服务列表里有seata-server但业务系统还是连不上先检查这里的namespace和客户端的namespace是否完全一致。5. 启动Seata-server并完成连通性验证5.1 Linux/Windows启动命令与启动日志关键点Linux下进入bin目录直接执行cd /opt/seata/bin sh seata-server.sh -p 8090 -h 127.0.0.1 -m db-p指定服务端端口-h指定对外发布的host-m指定存储模式。如果配置已经写在file.conf里其实不加参数也会读取配置文件。-h要特别注意如果这台机器会被其他机器上的服务访问-h不能写成127.0.0.1要写成这台机器对外的IP地址不然其他服务从Nacos拿到注册地址后连不上。Windows下双击seata-server.bat即可但如果要用-m db模式建议在命令行窗口手动执行这样能直接看到彩色日志输出。启动成功后日志里会有类似的提示表示Netty端口绑定成功并且服务已经对外提供服务。我建议把日志级别调到debug观察一段时间因为info级别下很多连接细节看不到比如RM注册成功、TM发起全局事务的握手日志。5.2 三步验证端口、日志、Nacos服务列表启动之后不要急着就去改业务代码先做三步验证。第一步确认端口在监听。Linux下用ss -lntp | grep 8090如果能看到LISTEN状态说明服务端进程已经起来了。第二步看日志里有没有异常堆栈。1.2版本启动失败最常见的报错是数据库连不上、无法加载驱动类、端口被占用日志会把原因打在最后几行。第三步去Nacos控制台的服务列表里找seata-server确认服务已经注册。这一步很好用因为即使Seata进程还活着注册不成功的话客户端也找不到它。如果这三步都正常就可以在客户端配置里把tx-service-group指到刚才的事务分组然后启动业务服务。观察Seata-server日志如果出现类似register branch success或者transaction begin success的日志说明TM和RM已经和TC建立起通信链路了。5.3 客户端file.conf如何对准server业务端的配置同样要有registry.conf和file.conf。客户端的registry.conf核心和服务端一致注册中心都要指到同一个Nacos客户端的file.conf里要配置tx-service-group然后用vgroupMapping映射到default集群。如果客户端也使用Nacos注册中心那么default.grouplist并不是必需的因为客户端会从Nacos发现服务端地址。这里容易踩的坑是客户端配置里的vgroupMapping名字写成了my_tx_group但tx-service-group填的是my_test_tx_group两个名字对不上。这个映射本质上就是给客户端一个寻址标记两边的字符串必须完全一致。我在项目里习惯把名字统一叫my_test_tx_group命名里有下划线时也要注意复制粘贴别弄混。6. 1.2版本安装实战中最高频的几个报错和解决路径6.1 Table xxx doesnt exist——初始化脚本漏跑了这个报错不用看完整堆栈基本可以断定是三张表没建或者建到了别的库。有位同学跟我反馈过他明明执行了脚本结果Seata-server仍然连不上数据库表后来发现他把脚本在seata库执行了但file.conf里的url却写成了jdbc:mysql://127.0.0.1:3306/test表全建到了seata库里。解决办法就是把url里的库名改成表实际存在的库或者把表统一迁移到url指向的库。如果是业务系统在回滚时抛Table undo_log doesnt exist那问题不在Seata-server而在客户端所在的业务库。AT模式要求每个接入Seata的业务数据库都有一张undo_log表这张表是用来记录回滚镜像的。这张表缺失时事务执行可能没问题但一旦触发回滚就会报错。解决办法是在业务库里执行客户端的undo_log建表脚本脚本同样在Seata源码的script/client目录下。6.2 Nacos连接正常但客户端一直重连TC——vgroup映射不对客户端日志反复出现Reconnect或者can not connect to serviceserver时先别怀疑网络。检查顺序应该是客户端tx-service-group是否和服务端registry.conf里的cluster一致客户端vgroupMapping的名字是否和tx-service-group匹配客户端的Nacosnamespace是否和服务端一致。我在一个模拟项目里排查过这类问题服务端日志和Nacos控制台都正常但客户端就是连不上TC。后来逐行对比配置发现客户端registry.conf里cluster写成了default服务端registry.conf里cluster却被前人改成了hangzhou两边名字对不上客户端按组名去Nacos找实例自然找不到。6.3 server启动就退出的另一类常见原因Seata-server启动直接退出的情况九成和端口、驱动、数据库地址有关。先看logs目录下有没有seata-server.log看最后一条异常。如果能看到Address already in use说明端口被占用换个端口或者杀掉占用的进程。如果是ClassNotFoundException检查lib目录下有没有对应的MySQL驱动jar。如果是Communications link failure检查url里的IP、端口、账号密码是否真的能连通。还有一类比较隐蔽的是内存不足。1.2版本的启动脚本里默认JVM参数可能配得比较大低配置服务器上启动时直接OutOfMemoryError然后进程退出。解决办法是打开bin/seata-server.sh把-Xms和-Xmx调小比如改成512M按需调整即可。7. 装完之后我建议你马上做的几项检查7.1 把file模式改成db模式再压测很多人在本地用file模式跑通了就以为大功告成等到预发环境一压测Seata-server一重启一些悬挂的全局事务状态就丢了。所以我建议装好之后马上切到db模式然后做一次简单的压测开两个服务一个服务里手动制造一个分支异常确认另一个服务的分支事务能正确回滚。回滚成功之后再去数据库里看global_table的状态字段确认已经从回滚中变成回滚完成。看到这个状态变化才能说明完整的协调链路是通的。7.2 先本地单机再考虑高可用集群1.2版本的Seata-server虽然可以搭集群但涉及Nacos集群和服务端多实例共享同一个db存储第一次配置很容易出问题。我个人的经验是先在一台机器上单机跑通全部业务场景再把同款配置复制到第二台机器同时启动看Nacos服务列表里是否出现两个seata-server实例。事务协调过程中客户端会从注册中心获取实例列表并随机连接其中一个只要两个实例连同一个数据库全局事务的状态就是共享的。7.3 日志级别调整和监控埋点Seata-server启动之后日志输出量不算小生产环境建议把日志级别调成info即可但在联动调试阶段可以临时调成debug因为debug日志里能看到XID的生成、分支注册的返回结果、全局事务的commit或rollback指令这些信息在排查“事务为什么没有回滚”时非常关键。最后给一个非常实用的建议在所有接入Seata的业务方法里把全局事务XID打到自己应用的日志里这样排查问题时把同一个XID串联起来就能清楚看到它经过哪些服务、在哪个分支失败。XID一般通过RootContext.getXID()获取加一行日志的问题但能为后面省大量时间。我每次搭建Seata环境都会顺手把这个埋点加上这算是装完Seata-server之后最值得做的一件小事。
阅读完成 · 觉得有帮助?
咨询建站