Apache Sandesha2 配置参数详解
逐项详解 Sandesha2 1.6.2 的 WS-RM 参数默认值、加载链与调参方法,参数取自源码实测并核验,如实标注 axis2.xml 顶层参数不生效等实测结论。
Apache Sandesha2 配置参数详解
目标:逐项讲清 Apache Sandesha2 1.6.2 的 WS-ReliableMessaging 参数——参数名、默认值、生效位置与调参方法,全部默认值与加载链路均取自 sandesha2-core-1.6.2 源码并在 Ubuntu 22.04 实测环境核验,跑不通的配置路径如实标注。
一、环境信息
本文参数清单与加载链路实测自以下环境(一台 Ubuntu 22.04 x86_64 服务器):
- 操作系统:Ubuntu 22.04(x86_64)
- JDK:OpenJDK 1.8.0_504
- Apache Axis2:1.6.2(
/opt/axis2-1.6.2,服务端 8080) - Apache Sandesha2:1.6.2(
org.apache.sandesha2:sandesha2-core:1.6.2jar 与 sources jar、sandesha2:1.6.2mar,Maven Central 原件) - 实测时间:2026-10-16
本文引用源码片段的获取方式(与实测一致):
cd /root/dl
curl -O https://repo1.maven.org/maven2/org/apache/sandesha2/sandesha2-core/1.6.2/sandesha2-core-1.6.2-sources.jar
unzip -oq sandesha2-core-1.6.2-sources.jar "org/apache/sandesha2/Sandesha2Constants.java" -d /root/materials
💡 说明:Sandesha2 1.6.2 没有独立的
sandesha2.xml配置文件,RM 参数分布在四个位置:模块内的 Policy 断言(SandeshaPolicyBean)、module.xml 模块参数、axis2.xml 的 phase/moduleConfig 结构、以及客户端Options运行时属性。很多旧资料提到的"sandesha2.xml"是 1.x 早期版本(1.0~1.1 时代)的文件,1.6.2 中已不存在,本文以 1.6.2 真实结构为准。
二、前置条件
- 已按《Apache Sandesha2 在 Ubuntu 22.04 集成使用指南》完成 Axis2 1.6.2 + Sandesha2 1.6.2 部署(模块加载成功、RM 示例服务可访问)。RM 服务可访问的验证命令与实测回显:
curl -s http://127.0.0.1:8080/axis2/services/Version
<ns:getVersionResponse xmlns:ns="http://axisversion.sample"><ns:return>Hi - the Axis2 version is 1.6.2</ns:return></ns:getVersionResponse>
- 已解包 sandesha2 模块查看 module.xml(参数与 handler 挂载点的第一手材料):
mkdir -p /root/materials && cd /root/materials
unzip -oq /root/dl/sandesha2-1.6.2.mar META-INF/module.xml
grep -n "parameter" META-INF/module.xml
实测回显:
176: <parameter name="propertiesToCopyFromReferenceMessage" locked="false">TransportURL,WSAddressingVersion,disableAddressingForOutMessages,rampartPolicy,RECV_RESULTS,PROXY</parameter>
177: <parameter name="propertiesToCopyFromReferenceRequestMessage" locked="false">WSAddressingVersion,RECV_RESULTS,rampartPolicy</parameter>
即 module.xml 中只有上述两个模块级参数,其余全部 RM 调优参数走 Policy 断言与客户端属性,这正是 1.6.2 的参数体系形态。
三、参数查看与修改方式
3.1 参数加载链(源码实测)
1.6.2 运行时读取 RM 参数的入口是模块初始化 SandeshaModule.init,加载链实测自源码(org/apache/sandesha2/SandeshaModule.java 关键行):
SandeshaPolicyBean constantPropertyBean = new SandeshaPolicyBean ();
SandeshaPolicyBean propertyBean = PropertyManager.loadPropertiesFromModuleDescPolicy(module,constantPropertyBean);
随后服务/操作级的覆盖走 PropertyManager.loadPropertiesFromAxisDescription(axisDescription, parentPropertyBean)——即从 Axis2 的 Policy 对象中寻找 SandeshaPolicyBean 断言。
由此得到修改参数的三条真实路径:
| 修改路径 | 作用域 | 是否实测验证 |
|---|---|---|
客户端 Options.setProperty(SandeshaClientConstants.X, ...) | 单个客户端/序列 | ✅ 实测(SEQUENCE_KEY/LAST_MESSAGE 跑通 RM 序列) |
WS-Policy 中的 RMAssertion 断言(SandeshaPolicyBean) | 服务/操作级 | ✅ 加载链源码实测(init 调用点) |
module.xml <parameter> | 模块级 | ✅ 文件实测(仅 3.1 节两个参数) |
实测确认一条不成立的路径:在 axis2.xml 顶层写 <parameter name="RetransmissionInterval">... 并直接调用内部 API PropertyManager.loadPropertiesFromModuleDesc(axisConfig.getModule("sandesha2")) 读取,实测抛出:
Exception in thread "main" java.lang.NullPointerException
at org.apache.sandesha2.util.PropertyManager.loadPropertiesFromModuleDesc(PropertyManager.java:83)
原因:该方法按 desc.getParameter(...) 逐个取参数并直接 .getValue(),axis2.xml 顶层 parameter 与模块描述并不挂接;1.6.2 运行时初始化走的是 3.1 节的 Policy 路径。结论:1.6.2 不要把 RM 参数写进 axis2.xml 顶层,这条与部分旧版资料的说法不同,以本文实测为准。
3.2 运行时参数查看方法
用最小客户端程序把模块当前生效的 QoS 值打印出来(核对默认值的实测手段)。保存为 DumpProps.java:
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.axis2.description.AxisModule;
import org.apache.axis2.engine.AxisConfiguration;
import org.apache.sandesha2.policy.SandeshaPolicyBean;
import org.apache.sandesha2.util.PropertyManager;
public class DumpProps {
public static void main(String[] args) throws Exception {
ConfigurationContext ctx = ConfigurationContextFactory
.createConfigurationContextFromFileSystem(args[0], args[1]);
AxisConfiguration axisConfig = ctx.getAxisConfiguration();
// 用默认值构造器直接生成当前默认 QoS(与 SandeshaModule.init 兜底逻辑一致)
SandeshaPolicyBean bean = new SandeshaPolicyBean();
System.out.println("RetransmissionInterval=" + bean.getRetransmissionInterval());
System.out.println("AcknowledgementInterval=" + bean.getAcknowledgementInterval());
System.out.println("InMemoryStorageManager=" + bean.getInMemoryStorageManagerClass());
System.out.println("SecurityManager=" + bean.getSecurityManagerClass());
}
}
编译与运行(classpath 与集成指南客户端一致):
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH
CP=$(ls /opt/axis2-1.6.2/lib/*.jar | tr '\n' ':')/root/rmclient/repository/modules/sandesha2-1.6.2.mar:/root/rmclient/classes
javac -cp "$CP" -d /root/rmclient/classes DumpProps.java
java -cp "$CP" DumpProps /root/rmclient/repository/ /root/rmclient/repository/client_axis2.xml
实测回显(log4j 告警可忽略):
RetransmissionInterval=6000
AcknowledgementInterval=3000
InMemoryStorageManager=org.apache.sandesha2.storage.inmemory.InMemoryStorageManager
SecurityManager=org.apache.sandesha2.security.dummy.DummySecurityManager
与源码默认值一致,说明 SandeshaPolicyBean 无参构造即承载官方默认值。
四、参数总览
以下参数名与默认值逐条转录自 sandesha2-core-1.6.2-sources.jar 的 Sandesha2Constants.java(Properties 与 DefaultValues 两个接口,实测 grep -A35 "interface DefaultValues" 回显):
| 参数名 | 默认值 | 含义 |
|---|---|---|
| RetransmissionInterval | 6000 | 重传间隔(毫秒) |
| AcknowledgementInterval | 3000 | 确认间隔(毫秒) |
| ExponentialBackoff | true | 重传指数退避 |
| InactivityTimeout | -1 | 序列不活动超时(-1=不限) |
| InactivityTimeoutMeasure | seconds | 不活动超时单位 |
| SequenceRemovalTimeout | -1 | 终止后序列清理超时(-1=不限) |
| SequenceRemovalTimeoutMeasure | seconds | 清理超时单位 |
| InMemoryStorageManager | org.apache.sandesha2.storage.inmemory.InMemoryStorageManager | 内存存储管理器 |
| PermanentStorageManager | org.apache.sandesha2.storage.inmemory.InMemoryStorageManager | 持久存储管理器(默认同内存实现) |
| InvokeInOrder | true | 服务端按序投递 |
| MessageTypesToDrop | VALUE_NONE | 丢弃的消息类型(默认不丢) |
| RetransmissionCount | 8 | 重传次数(内部上限参考值) |
| MaximumRetransmissionCount | 10 | 最大重传次数 |
| EPRDecorator | org.apache.sandesha2.addressing.EPRDecoratorImpl | EPR 装饰器类 |
| SecurityManager | org.apache.sandesha2.security.dummy.DummySecurityManager | 安全管理器 |
| ContextManager | org.apache.sandesha2.context.DummyContextManager | 上下文管理器 |
解读:默认值组合构成"每 6 秒重传、每 3 秒批量确认、指数退避、不限序列超时、内存存储、按序投递"的基线行为——适合功能验证;生产化需要按第六节模板显式收紧。
两层"默认值"的差异(实测核对,重要):DefaultValues 常量只是代码兜底,真正随模块加载生效的是 module.xml 内置的 RMPolicy 断言(见 5.7 节全录)。两者有三处不同:
| 参数 | DefaultValues 常量 | module.xml RMPolicy(实际生效) |
|---|---|---|
| ExponentialBackoff | true | false |
| InactivityTimeout | -1(不限) | 60(秒) |
| SequenceRemovalTimeout | -1(不限) | 600(秒) |
解读:SandeshaModule.init 先以 module.xml 的 RMPolicy 构造 SandeshaPolicyBean,常量兜底只在断言缺失时使用,因此运行时真实默认以 RMPolicy 列为准(如序列闲置 60 秒即被清理,而不是"不限")。
五、核心参数分类详解
5.1 重传与确认(发送侧节奏)
- RetransmissionInterval(默认 6000 毫秒):发送方未收到确认时两次重传的间隔。调小加快丢包恢复,但增加无谓流量;调大则网络抖动下恢复慢。
- AcknowledgementInterval(默认 3000 毫秒):接收方批量发确认的窗口。调小确认更及时(发送方可尽早释放待重传消息),调大减少确认报文数量。
- ExponentialBackoff(默认 true):重传间隔按指数放大(6s→12s→24s…),避免对端长时间不可达时重传风暴;置 false 则固定间隔重传。
- MaximumRetransmissionCount(默认 10)/ RetransmissionCount(默认 8):单条消息最大重传次数上限,超过后该序列进入故障。对延迟敏感场景可适当调大。
💡 技术拓展:重传策略不止指数退避一种——
策略 原理 取舍 固定间隔 每次重传等固定时间 实现简单,拥塞时压力大 指数退避(Sandesha2 默认) 间隔逐次翻倍 平稳,恢复速度前慢后稳 退避+抖动 翻倍基础上加随机量 防多客户端同步重传(Snow 雪崩) Sandesha2 1.6.2 仅提供固定/指数两档(
ExponentialBackoff开关),不支持抖动参数,本文即采用其默认指数退避。
5.2 序列生命周期
- InactivityTimeout(默认 -1,不限)+ InactivityTimeoutMeasure(默认 seconds,可选 seconds/minutes/hours/days):序列在指定时长无消息活动后判定不活跃并被清理。生产建议显式设置(如 600 秒),防止僵尸序列占用内存。
- SequenceRemovalTimeout(默认 -1,不限)+ Measure(默认 seconds):序列终止(TerminateSequence)后保留元数据的时长,超时后清除。有对账需求时可延长。
5.3 投递语义(接收侧)
- InvokeInOrder(默认 true):服务端是否严格按序投递给业务服务。置 false 后并发乱序投递提升吞吐,但依赖"消息幂等/可乱序"的业务前提。本文实测场景(按序累积拼接)依赖默认 true。
- MessageTypesToDrop(默认 VALUE_NONE):调试用,指定丢弃的 RM 消息类型,用于手工制造丢包验证重传,生产保持默认。
5.4 存储管理器
- InMemoryStorageManager(默认 org.apache.sandesha2.storage.inmemory.InMemoryStorageManager):序列状态(RMSBean/RMDBean/SenderBean 等)全部存内存,进程重启即失。
- PermanentStorageManager(默认同样指向内存实现):可替换为数据库实现以获得跨重启恢复。替换方式为 Policy/模块参数把类名指到自实现的
org.apache.sandesha2.storage.*子类,1.6.2 发行件未附带数据库实现——这一替换路径本文未做实测,如需持久化请自行实现并验证。
5.5 安全与扩展类
- SecurityManager(默认 org.apache.sandesha2.security.dummy.DummySecurityManager):RM 安全钩子;与 Rampart 集成时替换为 rampart 集成实现(artifact
sandesha2-rampart-integration提供),未配 Rampart 时保持 dummy。 - ContextManager(默认 DummyContextManager):上下文管理扩展点,默认实现即空操作。
- EPRDecorator(默认 EPRDecoratorImpl):控制匿名 EPR 改写;配合
EnableRMAnonURI(客户端属性)用于匿名 RM 场景。
5.6 客户端运行时属性(Options 层)
实测验证过的两个关键属性(本值即《集成使用指南》4.4 节跑通所用):
| 属性 | 实测取值 | 作用 |
|---|---|---|
| SandeshaClientConstants.SEQUENCE_KEY | "sequence3" | 把多条消息编入同一 RM 序列 |
| SandeshaClientConstants.LAST_MESSAGE | "true" | 标记最后一条,触发序列关闭 |
另有 RM_SPEC_VERSION(切 2005-02 / v1_1 规范版本)、OFFERED_SEQUENCE_ID(客户端预指定序列 ID)等属性,本文未实测,取值请参考 SandeshaClientConstants 常量定义(javadoc 与源码 jar 中均有)。
5.7 模块级 RMPolicy 与 axis2.xml 挂载点(实测全录)
module.xml 内置 RMPolicy 断言是 1.6.2 真实生效的模块级参数集。以下为从 sandesha2-1.6.2.mar 提取的 META-INF/module.xml 中 <wsp:Policy wsu:Id="RMPolicy"> 段原样转录(省略缩进注释):
<sandesha2:RMAssertion>
<wsp:Policy>
<sandesha2:AcknowledgementInterval>3000</sandesha2:AcknowledgementInterval>
<sandesha2:RetransmissionInterval>6000</sandesha2:RetransmissionInterval>
<sandesha2:MaximumRetransmissionCount>10</sandesha2:MaximumRetransmissionCount>
<sandesha2:ExponentialBackoff>false</sandesha2:ExponentialBackoff>
<sandesha2:InactivityTimeout>60</sandesha2:InactivityTimeout>
<sandesha2:InactivityTimeoutMeasure>seconds</sandesha2:InactivityTimeoutMeasure>
<sandesha2:SequenceRemovalTimeout>600</sandesha2:SequenceRemovalTimeout>
<sandesha2:SequenceRemovalTimeoutMeasure>seconds</sandesha2:SequenceRemovalTimeoutMeasure>
<sandesha2:InvokeInOrder>true</sandesha2:InvokeInOrder>
<sandesha2:MessageTypesToDrop>none</sandesha2:MessageTypesToDrop>
<sandesha2:StorageManagers>
<sandesha2:InMemoryStorageManager>
org.apache.sandesha2.storage.inmemory.InMemoryStorageManager
</sandesha2:InMemoryStorageManager>
<sandesha2:PermanentStorageManager>
org.apache.sandesha2.storage.inmemory.InMemoryStorageManager
</sandesha2:PermanentStorageManager>
</sandesha2:StorageManagers>
<sandesha2:SecurityManager>org.apache.sandesha2.security.dummy.DummySecurityManager</sandesha2:SecurityManager>
<sandesha2:ContextManager>org.apache.sandesha2.context.DummyContextManager</sandesha2:ContextManager>
<sandesha2:EPRDecorator>org.apache.sandesha2.addressing.EPRDecoratorImpl</sandesha2:EPRDecorator>
<sandesha2:MakeConnection>
<sandesha2:Enabled>true</sandesha2:Enabled>
<sandesha2:UseRMAnonURI>true</sandesha2:UseRMAnonURI>
</sandesha2:MakeConnection>
<sandesha2:EnforceRM>false</sandesha2:EnforceRM>
</wsp:Policy>
</sandesha2:RMAssertion>
逐项说明:MessageTypesToDrop/StorageManagers/SecurityManager/ContextManager 四项按源码注释声明为不可被服务级 Policy 覆盖;EnforceRM=false 表示服务未显式声明 RM 策略时不强制拒绝非 RM 消息;MakeConnection/UseRMAnonURI 开启匿名 RM 支持(对应服务列表中的 Sandesha2Operation* 虚拟操作)。要调参,把此断言复制进服务端 services.xml 的 <wsp:Policy> 引用并改值即可,加载链即三、1 节所述的 Policy 路径。
axis2.xml 中的 RMPhase 挂载点(模块 handler 的落脚处,实测 grep):
grep -n "RMPhase" /opt/axis2-1.6.2/conf/axis2.xml
466: <phase name="RMPhase"/>
483: <phase name="RMPhase"/>
513: <phase name="RMPhase"/>
522: <phase name="RMPhase"/>
分别位于 InFlow、OutFlow、InFaultFlow、OutFaultFlow 四条流——若手工裁剪 axis2.xml 导致任一 RMPhase 丢失,模块 handler 将无处挂载,RM 报文无法进入处理链。1.6.2 原版 axis2.xml 四处俱全,无需改动。
module.xml 注册的虚拟操作与 MEP 命名空间(实测转录,与《Apache Sandesha2 在 Ubuntu 22.04 集成使用指南》五、2 节的断裂报错直接相关):
<operation name="Sandesha2OperationInOnly" mep="http://www.w3.org/2006/01/wsdl/in-only">
<messageReceiver class="org.apache.sandesha2.msgreceivers.RMMessageReceiver"/>
<actionMapping>http://schemas.xmlsoap.org/ws/2005/02/rm/SequenceAcknowledgement</actionMapping>
<actionMapping>http://docs.oasis-open.org/ws-rx/wsrm/200702/CreateSequence</actionMapping>
</operation>
(仅节选两个映射,完整断言覆盖 2005-02 与 2007-02 两个规范的全部 RM Action,含 MakeConnection。)注意其 mep 属性使用 http://www.w3.org/2006/01/wsdl/ 命名空间——这正是 Axis2 1.8.x 拒绝该模块("An unsupported message exchange pattern (MEP) exists in ID is http://www.w3.org/2006/01/wsdl/in-only")的直接来源;Axis2 1.6.x 认可该命名空间,因此组合可用。
六、生产配置模板
适用场景:2C4G 以上、SSD 磁盘的 Ubuntu 22.04 服务器,Axis2 1.6.2 + Sandesha2 1.6.2,中等吞吐(每秒几十条 RM 消息)、需要按序可靠送达的内网 SOAP 服务。
1)JVM 内存收紧(axis2server.sh 第 35 行 JAVA_OPTS="" 处覆盖,堆控制在 256–512MB):
JAVA_OPTS="-Xms256m -Xmx512m -Xmn128m"
修改后用 jps -v 验证实际生效(实测形态):
jps -v | grep SimpleAxis2Server
2214 org.apache.axis2.kernel.SimpleAxis2Server -Xms256m -Xmx512m -Xmn128m
2)服务端 Policy 层收紧 RM 行为(在服务 aar 的 META-INF 下附加 wsp:Policy 引用 SandeshaPolicyBean 断言,或经代码构造 SandeshaPolicyBean 后 setParent 挂接):
<!-- 服务级 RMAssertion 建议基线(断言字段与默认值对照第四节) -->
<!-- RetransmissionInterval=6000, AcknowledgementInterval=3000,
ExponentialBackoff=true, InvokeInOrder=true,
InactivityTimeout=600s, SequenceRemovalTimeout=1800s -->
3)客户端按序列控制(实测跑通的最小属性集):
clientOptions.setProperty(SandeshaClientConstants.SEQUENCE_KEY, "order-20261016-001");
clientOptions.setTransportInProtocol(Constants.TRANSPORT_HTTP);
clientOptions.setUseSeparateListener(true);
clientOptions.setAction("urn:wsrm:EchoString");
// 最后一条消息触发序列终止
clientOptions.setProperty(SandeshaClientConstants.LAST_MESSAGE, "true");
要点:SEQUENCE_KEY 用业务单号前缀便于对账;LAST_MESSAGE 必须设置,否则序列不会终止、服务端序列状态长期驻留。
七、常见问题
Q1:参数写在 axis2.xml 顶层为什么不生效?
实测 1.6.2 的加载链是 SandeshaModule.init → loadPropertiesFromModuleDescPolicy(Policy 路径),不读 axis2.xml 顶层 parameter(见三、1 的 NPE 实测)。修改请走 Policy 断言或客户端 Options.setProperty。
Q2:改了重传参数如何确认生效?
用三、2 的 DumpProps 思路:构造 SandeshaPolicyBean 并把改后的 Policy 断言挂接后打印 getRetransmissionInterval() 等值;对照第四节默认值(6000/3000)观察变化。
Q3:InactivityTimeout 设小后客户端序列报什么错? 序列被判不活跃后,后续消息会触发 UnknownSequence 类 RM fault。该行为路径本文未实测复现(默认 -1 不会触发),如需启用建议先在测试环境验证。
Q4:storageManager 类名写错会怎样?
模块初始化/首次序列创建时抛 SandeshaException(类找不到),服务端日志可见完整栈。自定义存储实现务必先以独立 jar 放入 Axis2 lib 并通过 DumpProps 式程序先行加载验证。
八、参考链接
- Sandesha2 1.6.2 源码(本文参数唯一权威来源):https://repo1.maven.org/maven2/org/apache/sandesha2/sandesha2-core/1.6.2/sandesha2-core-1.6.2-sources.jar
- Sandesha2 模块包:https://repo1.maven.org/maven2/org/apache/sandesha2/sandesha2/
- WS-ReliableMessaging 1.2(OASIS,v1_1 规范的定稿版):https://docs.oasis-open.org/ws-rx/wsrm/200702/wsrm-1.2-spec-os.html
- 平台同系列文档:《Apache Sandesha2 介绍与选型指南》《Apache Sandesha2 在 Ubuntu 22.04 集成使用指南》