1. 先搞清楚:TongWeb8 的 bin 目录到底是干嘛的
接手一个用了国产中间件的项目,第一件事我向来是先翻安装目录,把 bin 和 logs 下的可执行文件、启动脚本逐个看清。TongWeb8 是东方通出的 Java 应用服务器,定位和 Tomcat、WebLogic 是一类东西,目录结构、部署方式大体上也走 J2EE 那套路子。平时你可以在管理控制台里部署应用、配数据源、看监控,但控制台起不来的时候,或者说还没把界面配置通的时候,真正能救你的就是 bin 目录下这一堆脚本。它们承担了中间件从“安装后”到“正常对外服务”的全部生命周期管理:启动、停止、查版本、注册服务、配置变更,全在这一层操作里。
这篇文章不打算复制官方文档,就按我实际使用的经验把这些脚本从头到尾理一遍,顺带把 JVM 参数、日志位置、常见坑也交代清楚。适合刚接触 TongWeb8 的开发、测试和运维同学,也适合准备把 TongWeb 从测试环境搬到生产环境的人参考。
下面讲的脚本清单基于我接触过的 TongWeb8 发行版本,不同小版本之间命名可能有差异,比如有的发行包把服务注册脚本合并成 service.sh,有的拆成 installService.sh / removeService.sh。你拿到安装包后可以先跑一条 ls 对照,功能定位是一致的。
1.1 按功能给脚本分个类
先别急着一个个背名字,理解 bin 目录的第一步,是把它当成“指挥中心”。里面的脚本按功能其实就四类:
- 启动类:startserver.sh / startserver.bat、firstStart.sh、startserver_noConsole.sh,负责把 JVM 拉起来,并选择合适的运行方式。
- 停止类:stopserver.sh / stopserver.bat,负责对运行中的实例下发停机命令,做优雅关闭。
- 服务与配置类:installService.sh / removeService.sh、dconfig.sh,负责把中间件注册成系统服务,或者调出图形化 / 命令行配置工具。
- 辅助诊断类:version.sh、jmxTool.sh 等,负责版本核对、JMX 检查、补丁验证。
这个分类方式能帮你快速定位问题:应用起不来就看启动类脚本和 logs;想确认补丁是否生效就去执行 version.sh;要开机自启就盯服务注册脚本。别把脚本当孤立的文件看,它背后对标的其实是“进程、端口、日志、服务”这四件事。
1.2 脚本管理和控制台管理怎么分工
很多人会问,TongWeb 不是带图形控制台吗,为什么还要用脚本?工程师之间对这个问题的理解其实很有共识:控制台解决的是“运行期管理”,比如部署应用、配置数据源、看连接池状态、实时调日志级别;而 bin 脚本解决的是“上线前和故障期”的场面。控制台上不去、启动失败、要做服务化改造,最后都回到脚本。
实际运维中,脚本方式还被自动化工具大量使用。因为脚本输出稳定、退出码可靠,可以被 CI/CD 流程直接调用;图形界面没法在每个平台都保证一致的自动化接口。所以我的建议是,控制台可以慢慢摸索,脚本至少要做到关键几步心里有数,不然真出故障时现查文档,时间根本不够用。
2. 启动、停止、服务注册:核心脚本逐个拆
2.1 startserver 与 startserver_noConsole,前台后台怎么选
startserver.sh 启动后会占据当前终端,把 JVM 运行日志直接打在控制台上。开发环境用起来很直观:起个服务,窗口里滚日志,出问题当场能看到异常堆栈。但在生产环境,这个方式有个大坑:终端一断开,服务进程就可能收到挂断信号直接退出。所以纯 startserver.sh 不适合长期驻留。
startserver_noConsole.sh 是去掉控制台绑定的启动方式,进程启动后转入后台,日志统一写到 logs 目录。生产机器上跑 TongWeb8,我推荐用这个脚本配合 systemd,后面第 6 节专门讲 systemd 的配置。另外,第一次在一个新环境启动时,我建议先用前台方式跑一把,确认 JVM 参数、配置文件没写错,再切到后台方式,不然一启动就退,日志里全是退出记录,反而难定位问题。
2.2 stopserver 的停止信号链路
stopserver.sh 看起来就一行命令,背后做的事却不简单。它并不是粗暴地杀掉进程,而是通过管理端口去连接运行中的中间件实例,发送一个停机指令。实例收到指令后,会先停止接收新的连接,接着把还在处理中的请求尽量处理完,再释放数据源、保存会话状态、注销各类监听器,最后才退出 JVM。
对业务来说,这个“最后才退出”很重要,特别是页面里带长事务、文件上传这种耗时操作的场景。直接 kill -9 看起来进程没了,但可能造成会话丢失、临时文件残留,严重的还会让数据库连接池留下半开的事务。所以平时要养成先跑 stopserver 的习惯,确实停不下来再考虑用系统命令处理。
2.3 服务注册脚本:让中间件开机自启
把 TongWeb8 装到服务器上,单机手动启动没问题,可如果是十几台机器,断电重启以后挨个去敲脚本就太原始了。TongWeb8 的 bin 目录里通常都有服务注册/移除脚本,Windows 下对应 installService.bat,Linux 下可能是 installService.sh,也有的发行包用 service.sh 统一管理。
服务注册的本质,是把启动命令包装成系统服务,交给系统守护进程接管。注册完成后,服务会随系统开机自动启动,进程意外退出后也能被自动拉起,对无人值守场景非常关键。配置服务时有一点必须注意:服务启动时的用户身份。Windows 服务如果用了权限过高的账号,数据库连接、文件写入偶尔会出权限问题;Linux 下推荐专门建一个业务用户,不要直接拿 root 跑中间件。
3. 实操:前置检查、JVM 参数与第一次启动
3.1 启动前检查清单
我每次部署 TongWeb8,都会在跑 startserver 之前花三十秒过一遍环境,比把错误留给日志去报强得多:
java -version echo $JAVA_HOME free -g df -h /data/tongweb netstat -tlnp | grep -E '80|8080|9060'前两条确认 JDK 和 JAVA_HOME,TongWeb8 对 JDK 版本有最低要求,装错版本启动脚本会直接报版本不支持。第三条看内存,第四条看磁盘,主要盯 logs 和部署目录所在分区。最后一条查端口,启动前确认端口没被其他服务占用。TongWeb8 的默认业务端口在不同发行包里可能不一样,网上的“默认 8080”说法不一定适用,最可靠的方式是看安装后生成的配置文件。
3.2 JVM 参数放哪里、改什么
TongWeb8 的 JVM 参数一般有两个入口:一是 bin 下启动脚本里预留的变量区,二是管理控制台的 server 配置。脚本方式适合安装阶段批量下发,控制台方式适合在线修改,但要真正生效通常得重启实例。
给一个我常用的参数模板:
export JAVA_OPTS="-Xms4096m -Xmx4096m -XX:MaxMetaspaceSize=512m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -Dfile.encoding=UTF-8 -Duser.timezone=GMT+08"-Xms 和 -Xmx 设成相同值,可以避免 JVM 运行中途反复扩充堆内存带来的性能抖动。Metaspace 根据应用加载的类数量适当调整,线上起步给 512m,类特别多的系统可以考虑再加大。GC 日志也要顺手开起来,方便以后排查内存问题:
-Xloggc:/data/tongweb/logs/gc_$(date +%Y%m%d).log -XX:+PrintGCDetails -XX:+PrintGCDateStamps需要提醒的是,具体参数名在不同 JDK 版本下略有区别,比如 JDK 8 用 PrintGCDateStamps,JDK 11 之后日志参数已经换了一套风格。改完参数后,用启动脚本拉起,再用 jps 或 ps 确认进程参数真实生效,这一步最可靠。
3.3 第一次启动的正确姿势
第一次启动建议用前台方式:
cd /data/tongweb/bin ./startserver.sh看到日志里出现类似 start successfully 的关键字后,可以先停在当前阶段观察,确认没有问题再换后台方式正式跑。后台方式我一般这样执行:
./startserver_noConsole.sh sleep 15 tail -n 200 logs/server.log为什么要等十几秒再查日志?因为中间件启动涉及初始化 Spring 容器、数据源、监听器,一个大型应用启动可能要几十秒,只有日志文件里出现明确的 ready 状态,才说明它真正起来了。如果立刻看 log,很容易误判“怎么没动静”。
应用部署完,浏览器访问http://服务器IP:端口/应用上下文验证。管理控制台的入口和账号初始化规则,首次登录时系统会给出提示,一定要第一时间修改初始密码,互联网上扫描默认密码的脚本远比想象中多。
3.4 版本核对和补丁验证
升级或打补丁后,第一时间要确认版本是否真的生效,别出现文件覆盖了、版本号没变这种尴尬事:
cd /data/tongweb/bin ./version.sh这个脚本会输出产品版本号、build 时间、JDK 信息。打补丁最怕的就是“以为打了补丁”,重启之后功能没变化,一通排查才发现补丁压根没被加载。我现在养成的习惯是启动前先跑一次 version.sh,启动后再跑一次,前后输出各留一份,排查问题时多一条明确线索。
4. 脚本机制拆解:优雅关闭、日志与 nohup 的区别
4.1 启动脚本的执行链路
启动脚本内部不是简单执行一个 java 命令,它要做的事包括:定位 JAVA_HOME、把 lib 目录下需要的 jar 全部拼进 classpath、加载系统属性和安全策略文件、检查配置目录是否存在、根据参数选择前台还是后台模式、必要时做端口检测和权限校验。
执行链路里最容易出错的是 classpath。中间件的类加载比较讲究,脚本里 classpath 的顺序如果乱了,后续应用部署时就会出现“类找不到”或者“类重复”的诡异问题。所以别轻易修改启动脚本里和 classpath 相关的内容,真要加外部 jar,优先通过管理控制台或脚本指定扩展目录,不要直接替换 bin 脚本的主体。
4.2 为什么 stopserver 比 kill -9 更安全
前面提过 stopserver 走的是管理端口信号,我再展开说一下。运行中的 JVM 会在管理端口上挂一个监听器,stopserver 脚本通过 socket 连接上去,发送指定命令。监听器收到命令后,把停机任务提交给内部的事件流程,依次触发应用各阶段的 shutdown 钩子,全部结束后进程自然退出。
这也是为什么 stopserver 偶尔会“停得慢”。一台机器上如果部署了多个应用,每个应用都在执行销毁清理,几十秒内进程退出都是正常的。怎么区分正常慢和卡死?观察日志:正常慢会有连续的清理日志,最后出现 shutdown complete;卡死通常是在某个清理阶段反复打同样的错误,或者长时间没有任何新日志。
4.3 日志重定向与 nohup 的差异
很多从 Tomcat 转过来的同学会习惯用 nohup 去拉服务:
nohup ./startserver.sh > /tmp/tongweb.log 2>&1 &短时间的临时调试可以,生产环境我不推荐。原因在于中间件本身实现了日志文件管理、按天滚动、错误日志分离,如果自己重定向到 /tmp,等于绕过了原来的日志体系,排错时还得额外找一份文件。
还有同学问 startserver_noConsole 是不是就是 nohup,其实两者层级不一样。noConsole 是产品层面的设计,它仍然管理自己的日志输出;nohup 是 shell 层面的转发。简单记:noConsole 适合稳定驻留,nohup 加 startserver 适合应急调试,别混为一谈。
5. 常见问题与排查技巧
5.1 问题速查表
| 症状 | 检查项 | 常见解法 |
|---|---|---|
| 启动即退出,无控制台窗口 | logs/server.log 尾部 | 查看最近异常堆栈,常见是配置错误或端口冲突 |
| 端口被占用 | netstat -tlnp / lsof | 停掉占用进程,或修改监听端口 |
| 提示 JAVA_HOME not found | 检查环境变量 | 设置 JAVA_HOME,或在脚本内显式指定 |
| 双击 bat 闪退 | 在 cmd 窗口手动执行 | 看具体报错,中文乱码调整编码 |
| 服务启动成功但访问 404 | 检查应用是否部署成功 | 确认部署目录形态与应用访问上下文 |
| 停止超时 | 查看 shutdown 日志 | 分析卡在哪个清理环节 |
| GC 日志过大 | 查看日志轮转配置 | 开启 GC 日志滚动,设置保留份数 |
5.2 典型场景:启动后立刻崩了怎么追
启动后几秒钟进程就消失,这是最常见的问题。我习惯按这个顺序排查:
- 先看 logs/server.log 的最后 200 行,找 out of memory、ClassNotFoundException、ConfigurationException 这类关键错误。
- 如果日志提示端口绑定失败,用
lsof -i:端口找到占用进程,确认是不是之前残留的实例没退干净。 - 如果日志提示配置解析错误,用配置工具检查最近的改动,可能是多加了一个不符合约束的配置项。
- 如果日志在启动过程中反复出现 JDK 版本检查失败,先
java -version确认默认 JDK,再确认 JAVA_HOME 指向是否正确。
第 3 类情况多发于手工改配置文件。TongWeb8 的配置有严格的 schema 约束,手工编辑时一个标签闭合错位,启动脚本并不会帮你预校验,而是等到解析配置时才报错。所以我一直建议,能用配置工具就尽量用工具,手工改完一定要保留一份启动日志做回归对照。
5.3 端口、防火墙和监控入口
部署到云服务器或内网服务器,端口配置是一道关卡。TongWeb8 对外服务端口、管理控制台端口、shutdown 停机端口,这三个最好都区分清楚。外网防火墙只开放业务端口,控制台限内网访问;停机端口更不能暴露,否则任何人都能远程把服务器停掉。
另外,中间件启动时连接外部系统(数据库、配置中心)的超时设置也值得关心。TongWeb8 默认会在启动时尝试初始化数据源,如果数据库不在线,启动过程可能一直挂着。这时候除了看日志,也可以先用最小配置把中间件拉起来,再逐步加入数据源,先定位是网络问题还是配置问题。这个方法我用了很多次,效率一直很高。
6. 生产环境利器:systemd 集成与服务化
6.1 Linux 下用 systemd 管理 TongWeb8
既然 noConsole 脚本适合后台驻留,下一步自然是用 systemd 把它管理起来。我一般会建一个专用的 tongweb 用户,然后写一个 unit 文件:
[Unit] Description=TongWeb8 Application Server After=network.target [Service] User=tongweb Group=tongweb WorkingDirectory=/data/tongweb ExecStart=/data/tongweb/bin/startserver_noConsole.sh ExecStop=/data/tongweb/bin/stopserver.sh Restart=on-failure RestartSec=10 LimitNOFILE=65535 [Install] WantedBy=multi-user.target配置好后执行:
systemctl daemon-reload systemctl enable tongweb systemctl start tongweb systemctl status tongwebExecStop 直接指向 stopserver.sh 而不是 kill,保证优雅关闭。Type 这里先用 simple 跑着观察,如果发现 systemd 认为服务已退出但 Java 进程还活着,说明 noConsole 脚本内部做了后台化,这时候要把 Type 改成 forking,并配置好 PIDFile。Restart=on-failure 加上后,进程闪退会被守护自动拉起,对业务连续性很有帮助。
6.2 Windows 服务模式的使用要领
Windows 上注册服务后,服务由系统服务管理器接管,同样能实现开机自启和异常重启。使用有一个高频坑:服务启动时找不到 JAVA_HOME。原因是 Windows 服务运行在独立会话里,读不到用户在操作系统界面里设置的临时变量。解决办法是把 JAVA_HOME 完整路径写入系统环境变量,或者在服务注册参数里显式指定。
另外,bat 脚本在中文 Windows 上偶尔会出现乱码。这往往是脚本文件编码和终端代码页不一致。先用编辑器确认脚本保存的编码,再把终端的代码页调整到对应编码去调试,不要直接凭感觉改脚本内容,改错一个字符比乱码更难查。
6.3 运维自动化的几个小习惯
最后分享几个我实际在用的习惯,都是文档里很少细讲但对稳定运维很有用的内容:
- 每次变更配置前,先备份 bin、config、lib 三个目录下要改动的文件,文件名加上时间戳。
- 把 version.sh 和启动日志纳入巡检脚本,每天检查一次版本号、启动时间、错误关键字。
- 启动脚本和停止脚本保留只读权限,避免日常误操作被改坏。
- 多实例部署时,用环境变量区分实例 ID,日志路径和配置路径按实例隔离,避免多个进程争抢同一份配置。
我个人在每个新环境里都会做一次“三连操作”:跑一遍 version.sh 确认版本,跑一下 startserver 确认启动参数,再跑 stopserver 确认能正常关闭。这三步不超过三分钟,却能把环境 80% 的初始问题排查掉,后续同事接手也少走弯路。