简介:WSO2 Enterprise Integrator 6.6.0中文使用手册面向企业集成架构师、ESB开发人员及需要从传统WSO2 ESB迁移到EI体系的工程师,围绕WSO2 ESB++企业集成方案展开。手册先梳理WSO2三款核心产品(API Manager、Enterprise Integrator、Identity Server)各自的定位与协作关系,让读者从整体生态理解EI;随后重点讲解EI 6.6.0的ESB配置文件与业务流程配置文件,涵盖短期无状态集成流和长期有状态业务流程(BPMN 2.0、WS-BPEL、人工任务)的实现思路,并通过REST代理、路由转发、REST转WebService、WebService转REST、TCP转WebService等典型场景说明消息转换与路由细节。文档还配有架构图,可辅助理解中介框架、多配置文件划分、EI-Analytics监控分析机制以及Apache 2.0开放许可带来的定制灵活性。资源包共1个doc文档,大小1.43MB,以独立文档形式提供,便于离线阅读、批注和按需检索,目前已有2041人浏览学习。对想快速上手WSO2 EI、把握ESB与数据集成结合点的读者,这份手册能明显降低官方英文文档的检索成本。
1. WSO2 EI 6.6.0 到底在解决什么问题
WSO2 Enterprise Integrator 6.6.0 是 WSO2 把 ESB、消息中间件、数据集成和流程编排打包到一套发行版里的整合产品,也是 WSO2-ESB 这条产品线在 6.x 时代最常被写进使用手册的版本。很多团队拿到使用手册.doc 的时候,真实处境是系统里既有 REST 接口又有老 SOAP 服务,还有定时跑批和数据库同步,每条链路都靠手写胶水代码硬撑,改一个字段要翻三个工程的代码。EI 6.6.0 要解决的就是把这类异构交互从业务代码里剥离出来,放到一个能可视化追踪、能灰度切换的消息层里。这篇笔记按“部署选型、消息流搭建、协议转换、故障排查、链路验证”的顺序,把能直接复用的做法和踩过的坑写清楚。
2. 部署前想清楚三件事:JDK、内存与发行包选型
2.1 为什么 6.6.0 值得从 6.5.0 迁过来
WSO2 Enterprise Integrator 6.6.0 是 WSO2 在 6.x 时代最后几个整合发行版之一,也是使用手册流传最广的版本。它和 6.5.0 相比,产品形态上最明显的变化在安装目录:wso2 目录下拆出了 broker、business-process、analytics、integrator 几个独立运行时,ESB 部分被明确收进 integrator profile。这个拆分直接缓解了老 WSO2 ESB 的一个老大难——以前 Proxy、流程引擎、分析模块全在一个实例里跑,启动慢不说,日志刷屏的时候你根本分不清是哪个模块在闹。
从实际项目看,6.5.0 迁到 6.6.0 的收益集中在依赖收敛。6.5.0 默认带的 Synapse 版本在 JSON 消息的 content-type 识别上偶尔会把 application/json 误判成 text/plain,导致下游服务收到格式不对的消息体。6.6.0 在这块收口得干净很多,HTTP 头处理也更接近主流网关的行为。CApp 部署包基本是兼容的,我迁移过几个带 Proxy、Sequence、registry 资源的项目,配置没有大改,真正的折腾点在第三方连接器。
这里要提醒一句:Salesforce、SAP、Kafka 这类跟外部 SDK 绑定的连接器,版本必须跟着 6.6.0 换。常见现象是启动时不报错,一旦消息走到对应 mediator 才抛 NoSuchMethodError 或 ClassNotFoundException。原因就是连接器打包时引用的 Carbon 版本和运行时不一致。所以我的习惯是先看连接器的 pom 或 .zip 包里的元数据,确认它标注的兼容版本,再决定要不要升级,而不是看到报错就直接去网上找新包。
另外,6.6.0 对 TLS 1.2 的默认开启也值得提。6.5.0 在部分 JDK 8 小版本上需要手动在 carbon.xml 里调整加密协议,6.6.0 默认就能过安全扫描。对要应对甲方安全评估的团队,这一点能省掉不少解释成本。
2.2 最小可用部署:目录结构、端口与启动命令
装 6.6.0 之前建议先花十分钟把目录看明白。发行包解压后,核心位置有三个:bin 目录放启动脚本和 setenv 入口,conf 目录放 carbon.xml、synapse.properties 等全套配置,repository/deployment 目录放 CApp 部署包以及 Proxy/API/Sequence 的热部署文件。理解这个结构的意义在于:很多人改了 conf 下的配置不生效,是因为 EI 的治理配置存在 registry(默认是本地 H2 数据库)里,registry 里的值会覆盖文件里的对应项。
最小验证环境我建议用一台 4 核 8G 的虚机,系统盘留 20G 以上,因为日志和 deployment 目录会慢慢涨。先做环境检查,再启动。
# 1. 确认 JDK 主版本,EI 6.6.0 只支持 JDK 8 java -version 2>&1 | head -n 1 # 期望输出: java version "1.8.x" 或 openjdk version "1.8.0_xxx" # 2. 解压发行包,注意路径不要带空格 unzip wso2ei-6.6.0.zip -d /opt/ export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 export CARBON_HOME=/opt/wso2ei-6.6.0 # 3. 以 integrator profile 启动 cd $CARBON_HOME/bin sh wso2server.sh -Dprofile=integrator这里的 -Dprofile=integrator 是关键。不指定 profile 时,6.6.0 会把 broker、analytics 一起带起来,内存占用轻松超过 3G,而且端口监听一大堆。绝大多数 ESB 集成场景只需要 integrator,显式指定后启动日志短、端口少、排查也方便。启动成功的标志是日志里出现 "WSO2 Carbon started in" 或 "Server started in"。如果卡在 "Starting WSO2 Carbon" 超过两分钟,优先怀疑内存不足或端口被占。
启动后立刻验证两个入口:
# 管理控制台,走 HTTPS,端口 9443 curl -k https://localhost:9443/carbon/ -o /dev/null -w "%{http_code}\n" # 返回 200 或 302 都算正常 # 消息入口,走 HTTP,端口 8280 curl http://localhost:8280/services/ -o /dev/null -w "%{http_code}\n" # 404 也是正常的,只要不是 connection refused8280 是 EI 默认的 HTTP 消息入口端口,9443 是控制台 HTTPS 端口。如果你本机已经跑了 Nginx 或 Tomcat 占了 8280,启动会直接报 "Address already in use"。改端口的位置在 conf/carbon.xml 的 Ports 段,里面有一个 Offset 偏移量参数。比如设成 10,8280 变 8290,9443 变 9453,所有端口一起偏移。这里有个易踩的坑:内部通信端口也会跟着偏移,如果后面要加 Analytics,记得两边 Offset 保持一致,否则数据上报连不上。
提示:改 Offset 后,控制台地址、服务入口和内部通信端口会一起偏移,后续加 Analytics 节点时必须保持两个实例的 Offset 一致,否则数据上报会静默失败。
2.3 JVM 参数与内存分配:这样调才不翻车
EI 6.6.0 基于 Carbon 4.4.x,运行时有两个内存敏感区:堆内存和 Direct Memory。Synapse 处理消息时大量走 NIO 的 ByteBuffer,所以看到 "Direct buffer memory" 的 OOM 时,光调 -Xmx 没用,必须动 MaxDirectMemorySize。这是比较多见的翻车点,默认 Direct 只有 256M,消息体一上 MB 级别,压测半小时准挂。
我一般不改 wso2server.sh,而是在 bin 目录下放 setenv.sh 覆盖默认值,这样以后升级 EI 版本不用重新比对启动脚本:
# $CARBON_HOME/bin/setenv.sh export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 export JAVA_OPTS="-Xms2G -Xmx2G -XX:MaxDirectMemorySize=1G \ -XX:+UseG1GC -XX:MaxMetaspaceSize=512m \ -Djava.awt.headless=true"-Xms 和 -Xmx 设成一致,避免运行时堆扩容触发 Stop-The-World。MaxDirectMemorySize 给 1G 是起步,如果消息体经常是几个 MB 的 XML 或 JSON,给到 2G,但前提是物理内存够用。MaxMetaspaceSize 设 512m 是防连接器 class 加载过多把 metaspace 撑爆。G1GC 在 JDK 8 上是稳妥选择,CMS 在 6.6.0 里已经不推荐,日志里会出现 deprecated 提示。
改完参数后,用 jstat 验证是否生效:
jps -l # 拿到 Java 进程 PID jstat -gcutil <pid> 1000 5 # 观察 FGCT 列,如果持续增长说明堆不够还要盯着一个比堆更隐蔽的指标:进程 RSS。用 top 看 RES 列,如果 RES 接近物理内存上限而堆利用率才 60%,那多半是 Direct Memory 或线程栈吃掉了。EI 默认的 worker 线程池是 120 个,开发环境完全用不了这么多,可以在 conf/synapse.properties 里把 synapse.threads.core 和 max 调小到 16 和 32,能省出一大块内存。这个参数知道的人不多,默认值是按生产集群设计的,单机跑就是浪费。
3. 把第一条消息流搭起来:Proxy、Sequence 与 Endpoint 的最小闭环
3.1 在控制台里创建 Proxy 的操作路径
EI 6.6.0 里最核心的复用单元是 Proxy Service。它本质上是一个虚拟服务,暴露在 EI 自己的 HTTP/HTTPS 端口上,外部调用它,它负责把消息转给后端的真实服务,再把响应带回来。Proxy 的价值在于:后端地址变了,你只需要改 EI 里的 Endpoint,不用动任何调用方代码。
图形化创建路径是登录 https://localhost:9443/carbon/ 之后,进入 "Main -> Service Bus -> Proxy Service"。点 Create 之后,向导会要求填目标命名空间、传输协议(http/https 勾选)、以及后端 WSDL 或直接填地址。这里有个经验:如果不是做代码生成,不要勾 "Provide WSDL",手动创建一个空 Proxy 更干净,因为 WSDL 方式会自动生成一堆你根本用不到的默认 Sequence,后面排查反而碍眼。
创建完成后,EI 会在 repository/deployment/server/synapse-configs/default 下生成对应的 XML 文件。这个文件是热加载的,你可以直接用文本编辑器改它,保存后 EI 会在几秒内自动生效,不用重启。这个机制既是优点也是雷点——改错一个标签,文件会被置为 faulty 状态,控制台里能看到但不报具体错误,排查起来很费劲。
所以我建议:凡是走图形界面创建的资源,先导出 XML 看一遍再上线。控制台里每个 Proxy 列表项都有 "Inactivate" 操作,出问题先停用,再改文件,改完重新激活,比直接改文件安全得多。
3.2 最小透传 Proxy 的 XML:粘贴就能跑
如果不想在图形界面里点来点去,直接把下面这个 XML 存成 OrderProxy.xml,放到 repository/deployment/server/synapse-configs/default/proxy 目录下,等几秒就能在控制台看到它激活。
<?xml version="1.0" encoding="UTF-8"?> <proxy name="OrderProxy" startOnLoad="true" transports="https http" xmlns="http://ws.apache.org/ns/synapse"> <target> <inSequence> <log level="full" category="INFO"> <property name="CALLER" value="OrderProxy-IN"/> </log> <send> <endpoint name="BackendOrderEP"> <address uri="http://10.20.30.40:8080/order/soap" format="soap11"/> </endpoint> </send> </inSequence> <outSequence> <log level="full" category="INFO"> <property name="CALLER" value="OrderProxy-OUT"/> </log> <send/> </outSequence> <faultSequence> <log level="full"> <property name="FAULT" value="OrderProxy-FAULT"/> </log> </faultSequence> </target> </proxy>这个配置做了四件事:第一,inSequence 里先打一条全量日志,记录请求进来;第二,用 send mediator 把消息发到 10.20.30.40:8080 这个后端地址,format 指定 soap11,强制把消息按 SOAP 1.1 发送;第三,outSequence 里再打一条日志,然后把响应原样送回给调用方;第四,任何异常走 faultSequence,打印日志而不是让调用方干等超时。
这里最值得细看的是 format="soap11"。如果后端是 .NET 写的 SOAP 服务,常见的是 soap12,format 写错之后,后端会直接回 "Unsupported Media Type" 或者解析失败。EI 的 address endpoint 支持 soap11、soap12、pox、get 四种格式。拿不准的时候,可以用 pox(Plain Old XML)让 EI 不强制加 SOAP 信封,只做 XML 转发,兼容性最好。
另外,send mediator 后面必须跟着 endpoint 或直接写 address。如果 send 后面什么都不写,EI 会把消息发往消息头里保存的 WSA:To 地址,也就是调用方传入的地址,这在某些透传场景下是需要的,但对后端地址收敛是灾难——后端一改,所有调用方都要改。
3.3 关键参数说明与第一次调试
上面的 XML 里有几个参数决定行为边界,上线前必须逐个确认。startOnLoad="true" 表示 EI 启动时就加载这个 Proxy,如果设成 false,Proxy 存在但不可用,外部请求会 404。transports 控制协议入口,只写 https 的时候,HTTP 的 8280 端口请求进不来,这个配置在安全审计场景常用,但开发调试时经常忘记改回来。
日志是第一次调试最趁手的工具。上面的配置里 log level="full",它会打印整个消息体,包括 HTTP 头、SOAP 信封和 payload。调试阶段建议全量,上生产前一定要降级。降级方案是把 level 改成 custom,再用 property 只打印关键字段:
<log level="custom"> <property name="ORDER_ID" expression="//order/id/text()"/> <property name="BACKEND" expression="get-property('To')"/> </log>expression 用的是 XPath,//order/id/text() 这种写法在 SOAP 体上直接取值。这里有个坑:如果消息体是 JSON,XPath 默认取不到值,需要先把 messageType 转成 XML,或者改用 json-eval 表达式。EI 6.6.0 里 json-eval('$.orderId') 可以直接用在属性表达式里,不用额外配置。
第一次调试的步骤我一般是:先在本机用 curl 打 Proxy,确认能进去;再把后端地址随便指向一个不存在端口,看 faultSequence 是否触发;最后才接真实后端。这个顺序能快速区分是 EI 配置问题还是后端问题。curl 命令参考:
curl -X POST http://localhost:8280/services/OrderProxy \ -H "Content-Type: text/xml; charset=utf-8" \ -d @order-soap-request.xml \ -w "\n%{http_code}\n"返回里如果 HTTP 200 但 body 是 fault 报文,说明消息走到了 faultSequence;如果连接直接被拒,说明 Proxy 没有激活,先去控制台看 service 状态。
4. 用 API 和 Mediator 做协议转换:REST 到 SOAP 的完整示例
4.1 API 与 Proxy 的选型边界
很多人在 EI 里分不清什么时候用 API,什么时候用 Proxy。简单判断法:对外暴露的是 REST 风格资源,用 API;对外暴露的是 SOAP 服务或需要 WSDL 契约的,用 Proxy。API 在 EI 里的实现是基于 URI 模板和方法匹配的路由层,适合做 /order/create 这种 RESTful 入口,而 Proxy 更像是一个完整的虚拟 SOAP 服务。
实际项目里最常见的组合是:外层 API 接收 REST 请求,内部通过 mediator 转换成 SOAP 报文,再调用后端的 SOAP 服务。这种组合能让你在前端保持 JSON,后端保持 WSDL 契约不变,两边互不感知。6.6.0 的 API 定义支持 methods、uri-template、以及 filters 做方法级路由,比老版本灵活得多。
选型还要考虑一个现实因素:API 的 context 是全局唯一的,两个 API 不能有相同 context,否则后部署的会把先部署的顶掉。这个行为在控制台里不报错,只有日志里能看到 "conflict" 字样。我踩过一次,两个团队分别部署了 context 都是 /order 的 API,结果线上路由时灵时不灵,查了半天才发现是 context 冲突。
4.2 REST 到 SOAP 转换的完整配置
下面是一个实战里很典型的场景:前端提交 JSON 订单,后端是 SOAP 1.1 的老系统,要求在 EI 里完成协议转换。
<api name="OrderAPI" context="/order" xmlns="http://ws.apache.org/ns/synapse"> <resource methods="POST" uri-template="/create"> <inSequence> <!-- 1. 把 JSON 请求转成 SOAP 报文 --> <payloadFactory media-type="xml"> <format> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ord="http://order.demo.org"> <soapenv:Body> <ord:createOrder> <ord:orderId>$1</ord:orderId> <ord:amount>$2</ord:amount> </ord:createOrder> </soapenv:Body> </soapenv:Envelope> </format> <args> <arg evaluator="json" expression="$.orderId"/> <arg evaluator="json" expression="$.amount"/> </args> </payloadFactory> <!-- 2. 指定 Content-Type,避免后端不认 --> <property name="messageType" value="text/xml" scope="axis2"/> <property name="DISABLE_CHUNKING" value="true" scope="axis2"/> <!-- 3. 发往后端 SOAP 地址 --> <send> <endpoint name="LegacySoapEP"> <address uri="http://10.0.0.10:8080/ws/createOrder" format="soap11"/> </endpoint> </send> </inSequence> <outSequence> <!-- 4. 把 SOAP 响应转回 JSON 返回前端 --> <payloadFactory media-type="json"> <format>{"code": "$1", "orderId": "$2"}</format> <args> <arg evaluator="xml" expression="//ns:code/text()" xmlns:ns="http://order.demo.org"/> <arg evaluator="xml" expression="//ns:orderId/text()" xmlns:ns="http://order.demo.org"/> </args> </payloadFactory> <property name="messageType" value="application/json" scope="axis2"/> <respond/> </outSequence> </resource> </api>逐步解释这段配置。第一个 payloadFactory 做的事情是把前端传来的 JSON 里的 orderId 和 amount 抽出来,填进 SOAP 信封。media-type 指定输出格式是 xml,format 里 $1、$2 是占位符,按 args 的顺序映射。这里的关键是 evaluator="json" 加 expression="$.orderId",用的 JSONPath 语法,EI 6.6.0 默认支持,不用额外引库。
第二步设置 messageType 为 text/xml,这是很多老 SOAP 系统的硬性要求,它们只认 text/xml,不认 application/soap+xml。DISABLE_CHUNKING 设成 true 是因为部分老后端不支持 HTTP chunked 传输,尤其是一些 Java 1.4 时代的服务。
第三步把消息发出去。第四步是反向转换,把 SOAP 响应体里的 code 和 orderId 抽出来包成 JSON。注意这里 evaluator 换成了 xml,expression 是 XPath 写法,前面带上了命名空间 ns。XPath 取 SOAP 响应值的时候,命名空间前缀必须和实际报文一致,否则取出来是空字符串。这一点最容易翻车——报文里命名空间是 ord,表达式里写 ns,结果永远为空。
4.3 路由与容错:如何让消息失败时有后悔药
协议转换只是第一步,生产环境最怕的是后端超时或者挂掉。EI 里给 endpoint 配超时和失败处理是标准动作,但很多人只配了超时,没配失败分支,结果超时后消息直接进 faultSequence,调用方收到一堆堆栈。
推荐的 endpoint 配置带超时、挂起和失败分支:
<endpoint name="LegacySoapEP"> <address uri="http://10.0.0.10:8080/ws/createOrder" format="soap11"> <timeout> <responseAction>fault</responseAction> <duration>30000</duration> </timeout> <markForRemoval> <suspendErrorCodes>101004,101005</suspendErrorCodes> <suspendDuration>60000</suspendDuration> </markForRemoval> </address> </endpoint>timeout 里的 duration 是 30 秒,超过 30 秒后端没响应,走 responseAction=fault 进入失败处理。suspendErrorCodes 是当出现 101004(连接超时)、101005(连接拒绝)这类错误时,把这个 endpoint 临时挂起 60 秒,期间新的消息不会发往这个地址,而是直接走 faultSequence。
这种配置的效果是:后端故障时,EI 不会让所有请求都堵在超时上,而是快速失败,同时给后端 60 秒恢复窗口。要不要自动重试,我一般建议不要开启 EI 内置的重试,因为大多数业务场景里重试会造成重复订单,幂等没做好的系统会被重试打穿。真要有重试需求,在业务代码里做幂等控制,比在 EI 里盲目重发安全得多。
faultSequence 里也不要只打日志,至少返回一个明确的错误码给调用方。用 property 和 respond 组合:
<faultSequence> <property name="HTTP_SC" value="503" scope="axis2"/> <payloadFactory media-type="json"> <format>{"error": "backend unavailable", "code": 503}</format> </payloadFactory> <property name="messageType" value="application/json" scope="axis2"/> <respond/> </faultSequence>这里把 HTTP 状态码强行设成 503,并返回一段 JSON 错误体。调用方拿到 503 就知道是后端问题,不会误以为是参数错误。这是最容易实现、也最让调用方省心的失败兜底。
5. 线上避坑记录:启动失败、消息丢失与性能倒挂的排查
5.1 启动失败:端口冲突与 JVM 崩溃
现象:执行 wso2server.sh 之后,日志刷到一半进程退出,提示 "Address already in use" 或者干脆没有日志直接消失。
原因:最常见的是 8280 或 9443 被占用。很多机器上 8080 被 Nginx、8280 被其他 Java 服务占着,EI 启动时端口绑定失败,但错误信息混在一大堆日志里,不仔细看根本发现不了。另一个原因是 setenv.sh 里的 -Xmx 给得比物理内存还大,JVM 直接起不来。
解决:启动前先做端口预检:
ss -tlnp | grep -E '8280|8243|9443' # 如果端口被占,要么杀进程,要么改 Offset改 Offset 在 conf/carbon.xml 里,把 0 改成 10,所有端口平移。注意管理端口是 9443+10=9453,登录控制台的地址要跟着变。如果是内存问题,把 -Xms/-Xmx 调回物理内存的一半以内再启动。还有一种隐蔽情况是 JDK 版本不对,用了 JDK 11 启动时会直接抛 UnsupportedClassVersionError,这个错误在日志最顶行,很多人在中间段找半天。
5.2 消息在 Sequence 里“神秘失踪”的排查
现象:请求打到 Proxy 上,后端没有收到任何请求,日志里 inSequence 的 log 打了,但 send 之后的日志没有,消息像被吞了一样。
原因:这是 EI 里最典型的“黑匣子”体验。绝大多数情况是 send mediator 后面没有配 endpoint,消息按照默认的 WSA:To 地址发送,而客户端调用时没有带 SOAPAction 或 To 头,EI 找不到目标地址就把消息 drop 了。另一个常见原因是消息里含有非法的 XML 字符,Synapse 在构建消息体时失败,直接走了 faultSequence,但 faultSequence 里只打了日志没返回响应,调用方看到的就是连接超时。
解决:出现这类问题时,先把 faultSequence 的第一行改成发送兜底响应,确保能通过 HTTP 状态码感知到失败。然后开 EI 的传输层日志,在 conf/log4j2.properties 里把 synapse.transport 的日志级别调成 DEBUG,可以看到 EI 在哪个节点丢弃了消息:
# 编辑 conf/log4j2.properties # 把 logger.synapse-transport 的 level 从 INFO 调成 DEBUG # 然后重启,或者用 logging profile 动态调整日志里如果出现 "Message dropped" 关键字,基本就是地址解析失败。解决是在 inSequence 里显式设置 To 属性,不要依赖调用方传地址。用 property name="To" value="http://10.20.30.40:8080/order/soap" 写死后端地址,再配合 send,消息就不会丢。
5.3 连接器缺依赖:NoClassDefFoundError
现象:部署了一个带 Salesforce 连接器的 CApp,启动正常,但一调用对应 API 就抛 java.lang.NoClassDefFoundError,日志里指向连接器内部的某个类。
原因:EI 6.6.0 的连接器是独立打包的,连接器依赖的某些库(比如 HttpClient 版本、Jackson 版本)和 Carbon 运行时内置的版本冲突。EI 的类加载机制是 parent-first,运行时优先加载 Carbon 自带的类,连接器里同名的旧版类就被屏蔽了,于是方法签名对不上,抛 NoSuchMethodError 或 NoClassDefFoundError。
解决:先确认连接器版本是否声明兼容 EI 6.6.0。WSO2 的连接器商店里每个连接器都会标注兼容的 EI 版本,下载时选 6.6.0 对应的 zip。其次是检查 CApp 打包时是否把第三方依赖打进去了,如果没有,把依赖 jar 放到 repository/components/lib 目录下,重启生效。这个目录下的 jar 会被 Carbon 自动加载,优先级低于 Carbon 内核,但高于连接器内部。
5.4 性能倒挂:为什么压测一上去吞吐反而下降
现象:用 JMeter 压测 50 并发时吞吐量正常,一加到 200 并发,吞吐量反而掉到只有 50 并发的一半,错误率飙升。
原因:这个现象十有八九是线程池和队列配置不匹配。EI 默认的 worker 线程池上限是 120,如果压测并发超过这个值,新请求不是在排队而是直接被拒绝。另一个原因是 Direct Memory 不够,200 并发时每个请求都分配 Direct ByteBuffer,内存一紧张,GC 频繁,吞吐自然崩。还有一种相对隐蔽的情况是日志级别,生产环境还开着 log level="full",每个请求都打全量消息体,磁盘 IO 直接成为瓶颈。
解决:压测前先把 EI 的线程池调低再调高,找到当前机器的拐点。在 conf/synapse.properties 里:
synapse.threads.core=32 synapse.threads.max=64 synapse.threads.queue.length=256core 是常驻线程数,max 是峰值,queue.length 是等待队列。队列设 256 是为了让瞬时突发请求有缓冲,但注意队列越长,平均响应时间越难看,要配合压测结果调。另外把日志级别降下来,上生产前所有 mediator 的 log 改成 level="custom" 只打印关键字段。实测很多项目把这两件事做了之后,同样配置下吞吐能翻一倍以上。
6. 把链路钉死:SOAPUI 加日志的最终验证套路
我到现在每次改完 EI 的 Proxy 或 API,都不会直接拿真实调用方来试,先用 SOAPUI 把链路钉一遍。SOAPUI 的好处是能同时做 REST 和 SOAP 请求,还能写断言自动比对响应。新建一个项目,把 EI 的 Proxy 地址填进去:http://localhost:8280/services/OrderProxy。请求体用一份固定的订单 XML,断言里检查 HTTP 状态码是 200 且响应体里包含 orderId 字段。
SOAPUI 里最常用的是两个断言:SOAP Response 检查命名空间是否正确,XPath Match 检查返回值是否和预期一致。这两个断言能快速暴露 EI 层的问题,比如 payloadFactory 占位符写错、命名空间前缀不对,这些在调用方那边可能要等到联调才发现。
验证链路时日志比调试器好用。我一般开三个东西:第一,控制台里每个 Proxy 的 inSequence 里加一个 level="custom" 的 log,打印消息头里关键的 correlation ID;第二,在 conf/log4j2.properties 里把 org.apache.synapse 的日志级别从 INFO 调到 DEBUG,这样能看到每个 mediator 的进出记录;第三,如果涉及 HTTP 传输问题,再把 org.apache.synapse.transport.http.wire 调到 TRACE,可以直接看到原始 HTTP 报文。
这三个层级从业务到传输依次加深。日常验证只需要第一层,出问题才往第二层走,最后一层是查“后端收到了什么”的终极手段,能看到 EI 实际发出去的字节流,很多 content-type 不对、chunked 编码问题都是在这层定位的。看完记得调回 INFO,TRACE 日志在生产环境一天能写出几个 GB。
最后说一个我的习惯:每次上线 EI 改动前,先把改动的 XML 文件备份一份,记录改动时间和原因。EI 的 deployment 目录是热加载的,一个误操作可能让线上配置立刻变成 faulty 状态,这时有备份就能秒级回滚,等于给自己留了后悔药。这套验证和回滚流程跑顺之后,EI 6.6.0 在我这边基本没有再出过需要半夜救火的线上事故。希望帮到你。
本文还有配套的精品资源,点击获取