Apache Vysper 常用 CLI 命令与工具详解

Apache Vysper 0.7 常用 CLI 命令与工具详解:run.sh 启动停止、JVM 参数注入、jps/jstack 观测、日志与 stanza 报文、openssl 探测、XEP-0133 管理命令与非 Spring 内存运行时实测

Apache VysperApache VysperXMPPJavaUbuntu2026/10/16

Apache Vysper 常用 CLI 命令与工具详解

目标:把管理一台 Apache Vysper 0.7 服务器所需的全部命令行操作讲透——启动、停止、观测、日志、协议探测、在线管理命令,以及一个鲜为人知的非 Spring 内存运行时。所有命令与回显均在 Ubuntu 22.04 服务器实测。

一、bin/ 目录与 run.sh 启动脚本

发行包的命令行入口只有两个文件(实测 ls bin/):

run.bat
run.sh
setenv.sh

run.bat 是 Windows 等价物,Linux 上唯一入口是 run.sh。它是个经典的类 Unix 启动包装脚本,干三件事(关键行摘自实际文件):

[ -f "$BASEDIR"/bin/setenv.sh ] && . "$BASEDIR"/bin/setenv.sh
CLASSPATH=$CLASSPATH_PREFIX:"$BASEDIR"/config:"$REPO"/nbxml-0.7.jar:"$REPO"/vysper-core-0.7.jar:...
EXTRA_JVM_ARGUMENTS=""
exec "$JAVACMD" $JAVA_OPTS \
  $EXTRA_JVM_ARGUMENTS \
  -classpath "$CLASSPATH" \
  -Dapp.name="run.sh" \
  -Dapp.pid="$$" \
  -Dapp.repo="$REPO" \
  -Dbasedir="$BASEDIR" \
  org.apache.vysper.spring.ServerMain \
  "$@"

逐项解读:

环节说明
setenv.sh存在则 source,是配置 JAVA_HOME/JAVA_OPTS 的正规入口(默认发行包不带,需自建)
CLASSPATH逐个列出 lib/ 下 50 余个 jar + config/ 目录;没有用 lib/* 通配
CLASSPATH_PREFIX用户可注入的前缀 classpath——挂自研模块 jar 就写它
EXTRA_JVM_ARGUMENTS用户可注入的额外 JVM 参数,同样写在 setenv.sh
org.apache.vysper.spring.ServerMain真正的启动类:读 classpath:spring-config.xml 完成装配
$@位置参数原样传给 main,0.7 的 ServerMain 并不解析任何启动参数

注意两个坑:run.sh 里 REPO 默认是 $BASEDIR/lib,所以启动目录无关紧要,但 config/ 与 log/ 的相对路径解析基于 $BASEDIR(由脚本自身位置决定),移动目录不影响;-Dapp.pid=$$ 记录了 shell 的 PID——exec 之后就是 java 进程的 PID,可用它做进程定位。

二、启动与停止

2.1 前台启动(调试用)

cd /opt/vysper/vysper-0.7
bin/run.sh

控制台实时输出启动日志,从 Spring 上下文刷新到模块逐个加载:

07:21:10,309 | INFO  | org.springframework.context.support.ClassPathXmlApplicationContext | Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@76c0fd31: startup date [Fri Oct 16 07:21:10 GMT 2026]; root of context hierarchy
07:21:10,331 | INFO  | org.springframework.beans.factory.xml.XmlBeanDefinitionReader | Loading XML bean definitions from class path resource [spring-config.xml]

Ctrl+C 即退出。前台方式便于看报错,生产不用。

2.2 后台启动(生产方式)

cd /opt/vysper/vysper-0.7
nohup bin/run.sh > /root/vysper-opt.log 2>&1 &
sleep 12
ps -ef | grep [S]erverMain | cut -c1-120
ss -tlnp | grep 5222

实测输出:

root       4018       1  0 07:05 ?        00:00:05 /opt/jdk/jdk8u504-b01/bin/java -Xms256m -Xmx256m -classpath :/opt/vysper/vysper-0.7/conf ...
LISTEN 0      50                 *:5222            *:*    users:(("java",pid=4018,fd=107))

💡 技术拓展:ss 的 users:(("java",pid=4018,fd=107)) 直接把端口和进程对上了,这是确认"5222 到底是哪个实例在听"的最快方式。若启用了 BOSH,还应看到 8080。

2.3 停止与重启

Vysper 没有提供停止命令或管理接口,停止就是 kill 进程:

# 停止单实例(推荐,按 PID)
kill $(ps -ef | awk '/[S]erverMain/{print $2}' | head -1)

# 确认干净
ps -ef | grep [S]erverMain | wc -l

实测输出:

0

重启即先 kill 再 nohup,两步合起来的标准组合:

kill $(ps -ef | awk '/[S]erverMain/{print $2}') 2>/dev/null; sleep 3
cd /opt/vysper/vysper-0.7 && nohup bin/run.sh > /root/vysper-opt.log 2>&1 &
sleep 12 && ss -tlnp | grep 5222

kill 默认发 SIGTERM,JVM 正常退出,日志文件不会截断(log4j 的 Append=true),重启后继续追加。

⚠️ 一个实测出来的坑:端口占用时进程会变"僵尸"。 旧实例还监听 5222 时启动新实例,MINA 绑定失败抛异常,但主进程不会退出:

Caused by: org.apache.mina.core.RuntimeIoException: Failed to bind
        at org.apache.vysper.mina.TCPEndpoint.start(TCPEndpoint.java:...)

此时 ps -ef | grep ServerMain 能看到两个实例,端口仍归旧实例。处置:全部 kill 干净再启动。改配置前先停服务,是避免这个坑的最省事习惯。

三、JVM 观测工具

3.1 jps:确认进程与参数

/opt/jdk/jdk8u504-b01/bin/jps -lv | grep ServerMain

实测输出:

4018 ServerMain -Xms256m -Xmx256m -Dapp.name=run.sh -Dapp.pid=4018 -Dapp.repo=/opt/vysper/vysper-0.7/lib -Dbasedir=/opt/vysper/vysper-0.7

-lv 把 setenv.sh 注入的 -Xms256m -Xmx256m 展示出来,用于验证 JVM 参数是否真的生效(比翻日志可靠)。

3.2 jstack:线程快照

PID=$(ps -ef | awk '/[S]erverMain/{print $2}' | head -1)
/opt/jdk/jdk8u504-b01/bin/jstack $PID | grep -cE '^"'
/opt/jdk/jdk8u504-b01/bin/jstack $PID | grep -E '^"' | head -8

实测输出(启用 BOSH 的实例):

33
"Attach Listener" #22 daemon prio=9 os_prio=0 tid=0x000071ca94001000 nid=0x1567 waiting on condition [0x0000000000000000]
"DestroyJavaVM" #21 prio=5 os_prio=0 tid=0x000071cae400b000 nid=0x1512 waiting on condition [0x0000000000000000]
"HashSessionScavenger-0" #20 daemon prio=5 os_prio=0 tid=0x000071cae49ca000 nid=0x1531 in Object.wait() [0x000071cabedfe000]
"qtp728885526-19" #19 prio=5 os_prio=0 tid=0x000071cae49a9800 nid=0x1530 waiting on condition [0x000071cabeefe000]
"qtp728885526-18" #18 prio=5 os_prio=0 tid=0x000071cae49a7800 nid=0x152f waiting on condition [0x000071cabeffe000]
...

33 个线程里 qtp*(Jetty 线程池)与 HashSessionScavenger 来自 BOSH 模块内嵌的 Jetty 7——即使 BOSH 零连接,这些线程也存在;排查 CPU/内存问题时可据此区分 TCP 通道与 HTTP 通道的线程组。

3.3 jmap:实测失败路径

/opt/jdk/jdk8u504-b01/bin/jmap -heap $PID

实测输出(本机默认权限下失败):

Attaching to process ID 5389, please wait...
ERROR: ptrace(PTRACE_ATTACH, ..) failed for 5389: Operation not permitted
Error attaching to process: sun.jvm.hotspot.debugger.DebuggerException: Can't attach to the process: ptrace(PTRACE_ATTACH, ..) failed for 5389: Operation not permitted

jmap -heap 依赖 ptrace 系统调用,缺 CAP_SYS_PTRACE 能力(或内核 ptrace_scope 收紧)时会这样报错。处置:以 root 且 ptrace_scope=0 的常规服务器上可正常运行;受限环境下放弃 jmap,改用 3.1 的 jps 验证参数、3.2 的 jstack 看线程即可覆盖日常运维需求。同一环境下 jstack 能正常 attach,说明故障面只在 jmap 的 ptrace 依赖上。

四、日志工具

4.1 两个日志文件

cd /opt/vysper/vysper-0.7 && ls -l log/

实测输出:

-rw-r--r-- 1 root root  26411 Oct 16 07:25 stanza.log
-rw-r--r-- 1 root root 138884 Oct 16 07:25 vysper_server.log
文件内容用途
vysper_server.log服务器运行日志(模块加载、认证、路由异常)服务排障
stanza.log逐条 XMPP 报文摘要(方向+类型+关键参数)协议排障

两者按 config/log4j.xml 滚动:500KB 上限、保留 1 份备份(*.log.1)。长期运行需外接 logrotate 或调大 MaxFileSize。

4.2 实时盯报文:tail + stanza.log

tail -f /opt/vysper/vysper-0.7/log/stanza.log

发起一次登录与发消息后,实测滚动出:

INFO  07:25:58,263 | client | iq.id='d1'.to='vysper.org'.type='get'.query.disco.info
INFO  07:25:58,264 | server | iq.id='d1'.from='vysper.org'.type='result'.query.disco.info.feature='http://jabber.org/protocol/disco#info'.feature='jabber:iq:version'.feature='urn:xmpp:time'.feature='vcard-temp'.feature='urn:xmpp:ping'
INFO  07:25:58,265 | client | message.body.hello from user1 at 2026-10-16 07:25:58
INFO  07:25:58,267 | server | message.body.hello from user1 at 2026-10-16 07:25:58
INFO  07:25:58,304 | client | message.body.reply from user2
INFO  07:25:58,305 | server | message.body.reply from user2

client 是客户端发来的 stanza,server 是服务器回出的 stanza,一问一答成对出现。客户端"没收到消息"这类问题,先看这里能立刻区分是"没收到报文"还是"报文内容异常"。

4.3 控制台降噪:Threshold 调整

config/log4j.xml 中 CONS appender 的 Threshold 默认 TRACE,控制台很吵。改成 WARN 后重启:

sed -i '0,/<param name="Threshold" value="TRACE"\/>/s//<param name="Threshold" value="WARN"\/>/' config/log4j.xml
kill $(ps -ef | awk '/[S]erverMain/{print $2}') 2>/dev/null; sleep 3
cd /opt/vysper/vysper-0.7 && nohup bin/run.sh > /root/vysper-log4j-warn.log 2>&1 &
sleep 12
wc -l < /root/vysper-log4j-warn.log

实测输出:

5

同窗口 TRACE 阈值下控制台 60 余行、WARN 阈值下 5 行。只改 CONS 不影响 log/ 下两个文件,排障期记得改回 TRACE。

五、TLS 探测:openssl s_client

不带任何客户端就摸清服务端 TLS 状况,s_client -starttls xmpp 是最趁手的工具。

看流头与证书信任判定(默认安全级别,0.7 自带的 2005 年 511 位 MD5 证书会被直接拒绝):

echo | openssl s_client -starttls xmpp -connect 127.0.0.1:5222 2>&1 | sed -n '1,3p'

实测输出:

CONNECTION ESTABLISHED
SSL_connect:SSLv3/TLS write client hello
SSL_connect:SSLv3/TLS read server hello

查看完整校验结果需放宽安全级别后落地证书:

echo | openssl s_client -starttls xmpp -connect 127.0.0.1:5222 -cipher 'ALL:@SECLEVEL=0' 2>&1 | grep -E "subject=|Verification|New, "

实测输出:

subject=CN=montague.im, O=Assumed Security, OU=Functional Testing, C=US
Verification error: self-signed certificate
New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256

(CN=montague.im 是 2005 年生成 bogus 证书时留下的名字,这就是"罗密欧与朱丽叶"测试证书。)换上 2048 位新证书后(换法见《Apache Vysper 配置参数详解》第六节)无需任何放宽参数:

echo | openssl s_client -starttls xmpp -connect 127.0.0.1:5222 -servername vysper.org 2>/dev/null | grep -E "New, |Verification"
echo | openssl s_client -starttls xmpp -connect 127.0.0.1:5222 -servername vysper.org 2>/dev/null | openssl x509 -noout -subject -dates

实测输出:

New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Verification error: self-signed certificate
subject=CN=vysper.org, OU=Demo, O=Demo, L=Beijing, C=CN
notBefore=Oct 16 07:04:02 2026 GMT
notAfter=Oct 13 07:04:02 2036 GMT

Verification error: self-signed certificate 是自签证书的固有提示;关键信息是协议协商升到了 TLS 1.3、证书主体与有效期符合预期。把 -starttls xmpp 换成 -connect 直连 8080 可对 BOSH 端点做同类探测。

六、协议级排查:裸 XMPP 流 + stanza.log 双向核对

怀疑客户端行为不标准时,绕开客户端直接对服务器说话。最小探测脚本(python 标准库,只读流头):

python3 -c "
import socket
s = socket.create_connection(('127.0.0.1', 5222), 10)
s.sendall(b\"<?xml version='1.0'?><stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:client' to='vysper.org' version='1.0'>\")
print(s.recv(4096).decode()[:300])
s.close()"

实测输出:

<?xml version="1.0" encoding="UTF-8"?><stream:stream xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" from="vysper.org" version="1.0" id="7f3ca97451c546a3a86ee8f7ba8a1ef7"><stream:features xmlns:stream="http://etherx.jabber.org/streams"><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"><required></required></starttls><register xmlns="http://jabber.org/features/iq-register"></register></stream:features>

这个回显信息量很大:from="vysper.org" 确认域名;<starttls><required/> 说明明文通道只允许升级;<register/> 说明 XEP-0077 带内注册已启用。同一时刻 tail stanza.log 应出现对应的流头记录,两侧对不上就查网络中间层。

💡 技术拓展:XMPP 流是双向 XML 流,服务器对不合法 XML 或未按协议走的连接会直接断开并可能回 <stream:error>;裸流探测时逐条等应答、按 <required/> 顺序推进(STARTTLS → 认证 → 绑定),比一次性灌入全部报文更接近真实客户端行为。

七、在线管理命令:XEP-0133 服务管理

发行包默认启用了 XEP-0133 Service Administration(admin@vysper.org 在 addAdmins 列表)。它跑在 XEP-0050 ad-hoc 命令框架上,节点 http://jabber.org/protocol/admin#add-user 用于加用户,流程三步:execute 拿表单 → submit → completed。

完整可用脚本(/root/xep0133.py,依赖 B1 的连接骨架):

#!/usr/bin/env python3
# XEP-0133 add-user:execute 取表单 -> submit 提交 -> completed -> 新账号登录验证
import re
from xmpp_client import C, DOMAIN   # 复用 B1《安装指南》的 XMPP 客户端骨架

admin = C('admin', 'admin', 'q1w2e3r4')
admin.login('adminres')

# 1) execute:取表单
admin.send(f"<iq type='set' id='ex1' from='{admin.full_jid}' to='{DOMAIN}'>"
           f"<command xmlns='http://jabber.org/protocol/commands' "
           f"node='http://jabber.org/protocol/admin#add-user' action='execute'/></iq>")
r = admin.recv()
sid = re.search(r"sessionid='([^']+)'", r.replace('"', "'")).group(1)
print('form sessionid =', sid)

# 2) submit:字段名必须用 accountjid / password / password-verify
admin.send(f"<iq type='set' id='ex2' from='{admin.full_jid}' to='{DOMAIN}'>"
           f"<command xmlns='http://jabber.org/protocol/commands' "
           f"node='http://jabber.org/protocol/admin#add-user' sessionid='{sid}' action='complete'>"
           f"<x xmlns='jabber:x:data' type='submit'>"
           f"<field var='FORM_TYPE'><value>http://jabber.org/protocol/admin</value></field>"
           f"<field var='accountjid'><value>user3@{DOMAIN}</value></field>"
           f"<field var='password'><value>q1w2e3r4</value></field>"
           f"<field var='password-verify'><value>q1w2e3r4</value></field>"
           f"</x></command></iq>")
admin.recv()

# 3) 新账号登录验证
u3 = C('user3', 'user3', 'q1w2e3r4')
u3.login('u3res')
print('=== user3 LOGIN OK -> XEP-0133 add-user 生效')

执行 timeout 90 python3 xep0133.py,实测关键回显:

execute 应答的服务器表单(字段名就在里面,照抄即可):

<command ... status="executing"><x xmlns="jabber:x:data" type="form"><instructions>Fill out this form to add a user.</instructions><title>Adding a User</title>
<field var="FORM_TYPE" type="hidden"><value>http://jabber.org/protocol/admin</value></field>
<field var="accountjid" label="The Jabber ID for the account to be added" type="jid-single"/>
<field var="password" label="The password for this account" type="text-private"/>
<field var="password-verify" label="Retype password" type="text-private"/>
<field var="email" .../><field var="given_name" .../><field var="surname" .../></x></command>

submit 后的确认:

<iq ... type="result" id="ex2"><command ... sessionid="87581f1f7c8a46d6b29d5f90e9aae354" status="completed"></command></iq>

新账号立即登录:

=== [user3] login OK, full jid = user3@vysper.org/83072d57063443e28d013eb518471b98
=== user3 LOGIN OK -> XEP-0133 add-user 生效

两个实测注意点:① 字段名是 accountjid(单数、jid-single)——照抄较新 XEP-0133 修订的 accountjids 会得到错误应答;② 新账号落在当前存储注册器里,纯内存模式下重启即丢,持久化前提是先切 JCR 存储(《Apache Vysper 配置参数详解》2.1 节有跨重启存活的对照实测)。

八、用户自助注册:XEP-0077 带内注册

在 config/spring-config.xml 的 modules 列表加一行(详情见《Apache Vysper 配置参数详解》2.6 节):

<bean class="org.apache.vysper.xmpp.modules.extension.xep0077_inbandreg.InBandRegistrationModule"/>

重启后流特性出现 <register xmlns="http://jabber.org/features/iq-register"/>(第六节回显可见)。自助注册就是一条 iq:

timeout 90 python3 xep0077_final.py

实测关键回显:

>>> [reg] <iq type='set' id='r1' to='vysper.org'><query xmlns='jabber:iq:register'><username>user5</username><password>q1w2e3r4</password></query></iq>
<<< [reg] <iq xmlns="jabber:client" from="vysper.org" type="result" id="r1"></iq>
=== [user5] login OK
=== USER5 -> ADMIN MESSAGE OK (XEP-0077 on Spring runtime)

type='result' 即注册成功,新账号立刻能登录并投递消息(接收方必须在线——Vysper 0.7 没有离线消息存储,先发后上线的消息会被丢弃,这是实测确认过的行为差异,不是 bug)。

九、非 Spring 内存运行时:一行命令起一个 XMPP 服务器

发行包里还藏着一个不读 spring-config.xml 的启动类:org.apache.vysper.xmpp.server.ServerMain(注意与 run.sh 用的 org.apache.vysper.spring.ServerMain 区分)。它全内存运行、内置一组默认模块(含 XEP-0077 与 XEP-0133),两个系统属性控制行为:

系统属性作用
vysper.admin.initial.password初始 admin@vysper.org 的密码(必须设置,否则口令随机生成)
vysper.add.module额外加载的模块类名,逗号分隔多个

9.1 直接启动的失败路径(实测)

cd /opt/vysper/vysper-0.7
/opt/jdk/jdk8u504-b01/bin/java -Dvysper.admin.initial.password=q1w2e3r4 -cp "config:lib/*" org.apache.vysper.xmpp.server.ServerMain

实测输出:

Exception in thread "main" java.io.FileNotFoundException: src/main/config/bogus_mina_tls.cert (No such file or directory)
        at java.io.FileInputStream.open0(Native Method)
        at org.apache.vysper.xmpp.server.XMPPServer.setTLSCertificateInfo(XMPPServer.java:95)
        at org.apache.vysper.xmpp.server.ServerMain.main(ServerMain.java:90)

这个类把证书路径硬编码为 src/main/config/bogus_mina_tls.cert——那是源码工程的目录布局,二进制发行包里没有。这也是该类更适合开发者而非运维的证据。workaround 很简单,按它要的布局补一个:

cd /opt/vysper/vysper-0.7
mkdir -p src/main/config && cp config/bogus_mina_tls.cert src/main/config/

9.2 启动与验证

nohup /opt/jdk/jdk8u504-b01/bin/java -Dvysper.admin.initial.password=q1w2e3r4 \
  -cp "config:lib/*" org.apache.vysper.xmpp.server.ServerMain > /root/vysper-nonspring.log 2>&1 &
sleep 12
ss -tlnp | grep 5222
grep -m1 "adding module" /root/vysper-nonspring.log

实测输出:

LISTEN 0      50                 *:5222            *:*    users:(("java",pid=4836,fd=113))
07:15:21,140 | INFO  | org.apache.vysper.xmpp.server.DefaultServerRuntimeContext | adding module... XEP-0133 Service Administration (1.1)

在此实例上执行第八节的 XEP-0077 注册脚本,实测成功(注册应答 type="result"、user5 登录 OK)。

-Dvysper.add.module 动态加载 XEP-0060 PubSub:

/opt/jdk/jdk8u504-b01/bin/java -Dvysper.add.module=org.apache.vysper.xmpp.modules.extension.xep0060_pubsub.PublishSubscribeModule \
  -Dvysper.admin.initial.password=q1w2e3r4 \
  -cp "config:lib/*" org.apache.vysper.xmpp.server.ServerMain

实测日志:

07:16:30,468 | INFO  | org.apache.vysper.xmpp.server.DefaultServerRuntimeContext | adding module... XEP-0060 Publish-Subscribe (1.13rc3)

测试完 kill 掉并按第二节流程恢复 Spring 实例即可。这个运行时适合两个场景:不碰配置文件快速验证模块行为;本地开发时当一次性内存服务器。它同样监听 5222,与 Spring 实例不能并存。

十、演示程序实况:没有 demobot,有源码级 Swing 客户端

在 0.7 的二进制发行包与完整源码树里检索 demo/bot 关键字——如实给出阴性结论:发行包 bin/ 只有 run.sh/run.bat,lib/ 里没有任何 demo/bot jar;完整源码包(vysper-0.7-src.tar.gz)中与"演示"相关的只有两处:

tar tzf vysper-0.7-src.tar.gz | grep -E "vysper-0.7-src/(demo|examples)/" | cut -d/ -f2-3 | sort -u

实测输出:

demo/
demo/pubsub
examples/
examples/embedded-war
examples/pom.xml
位置内容实测状态
demo/pubsub/clientPubsubClientGUI——Swing 图形界面 XMPP 客户端,演示 XEP-0060 发布订阅源码级,需 Maven 构建(pom 声明的是 Maven 2 时代插件,本机未构建实测)
examples/embedded-war把 Vysper 内嵌进 Web 应用的 WAR 示例同上

所以:网上流传的「Vysper 自带 demobot 机器人」并不存在于 0.7 发行包;想看协议行为,最直接的就是本文第四节的 stanza.log + 第七、八节的脚本实测。如果需要,把《Ubuntu 22.04 安装 Apache Vysper 指南》第七节的 xmpp_client.py 改成循环读 stdin 发消息,十行代码就是一个小 bot——但那是自己写的,不是 Vysper 自带的。

十一、常用操作速查表

目的命令
启动(后台)cd /opt/vysper/vysper-0.7 && nohup bin/run.sh > /root/vysper-opt.log 2>&1 &
停止kill $(ps -ef | awk '/[S]erverMain/{print $2}')
确认端口ss -tlnp | grep 5222
确认 JVM 参数jps -lv | grep ServerMain
线程快照jstack $(pgrep -f ServerMain | head -1)
实时报文tail -f log/stanza.log
运行日志tail -f log/vysper_server.log
TLS 探测openssl s_client -starttls xmpp -connect 127.0.0.1:5222
流头探测python 裸流脚本(第六节)
在线加用户XEP-0133 脚本(第七节)
自助注册验证XEP-0077 脚本(第八节)
内存一次性实例第九节 java -D... org.apache.vysper.xmpp.server.ServerMain

至此,Vysper 0.7 日常运维所需的命令与工具已全部过完。安装过程见《Ubuntu 22.04 安装 Apache Vysper 指南》,配置项逐条含义见《Apache Vysper 配置参数详解》,产品定位与选型背景见《Apache Vysper 介绍与选型指南》。