尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Tomcat启动提示找不到APR本机库:影响评估与生产环境配置指南

Tomcat启动提示找不到APR本机库:影响评估与生产环境配置指南 如果你部署过Tomcat大概率在启动日志里见过这么一段提示The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path翻译过来就是“找不到基于APR的Apache Tomcat本机库”。前几天在客户现场部署新环境我又撞上了这个经典的Tomcat部署问题。项目最终倒是正常跑起来了但负责运维的同事反复问我这个提示到底要不要紧会不会影响线上性能配置不处理会不会出大事这个报错在Tomcat部署场景里极其常见属于典型的“看着吓人、处理起来也有讲究”的问题。它不会让Tomcat启动失败也不会直接导致项目无法访问但对生产环境而言不处理它会白白损失一部分性能尤其在HTTPS和静态资源场景下差距明显。这篇内容我把自己的排查思路、处理方案和踩过的坑整理出来帮你在下次部署时少走弯路。无论你是刚入门Java Web部署的新手还是被DevOps拉去救火的后端开发都可以直接按章节操作。1. 从启动日志看问题本质APR本机库是什么1.1 报错原文逐句拆解先把这个报错信息完整贴出来大家对照着自己日志看信息: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib]这段日志有几个关键信息。APR是Apache Portable Runtime的缩写Apache可移植运行时Apache Tomcat Native library是Tomcat为了性能优化引入的本地库我习惯简称为tc-nativejava.library.path则是JVM搜索本地库文件时使用的目录列表。这句话的完整含义是Tomcat在启动时尝试加载一个名为tcnative的本地库这个库能够提供比纯Java实现更优的性能但JVM在指定的所有路径里都没找到这个库文件。很多第一次接触的人会误解“找不到”是故障实际上Tomcat这里只是做了“能力探测”。它启动时会主动尝试加载APR库加载成功就切换性能更优的执行方式加载失败就自动回退到Java NIO模式继续运行。所以项目还能正常启动、访问原因就在这里。1.2 APR到底是什么为什么要基于它APR原本是Apache HTTP Server里的底层可移植运行库把不同操作系统上的文件IO、网络IO、线程管理、共享内存等底层操作进行统一封装。Tomcat团队意识到这个库的价值于是通过JNI方式把它引入到Tomcat里让Tomcat也能复用这些高性能的本地实现。用生活里的场景类比Java本身就像一个“万能翻译官”不管在Windows、Linux还是macOS上都能干活但它的每次文件读写都要经过一层比较重的抽象。而APR相当于直接找到当地最熟悉情况的“本地向导”哪里有不计其数的坑、哪条路最快向导一清二楚效率自然高得多。具体到Tomcat运行时使用APR后有几个最直观的变化静态资源处理传统NIO模式下需要经过Java堆内存多次拷贝APR可以直接利用操作系统sendfile调用静态文件能直接从磁盘发送到网卡减少内存拷贝和上下文切换吞吐量明显提升。SSL/TLS握手纯Java的JSSE性能相对一般APR直接调用OpenSSL握手性能提升非常明显尤其在大量短连接场景下。连接器扩展性APR在异步IO、文件上传、内存映射文件等方面都有优势对高并发、大文件场景更友好。所以结论很明确开发环境可以忽略这个告警生产环境建议处理尤其是项目涉及HTTPS、大量静态文件或高并发时处理收益远大于成本。2. Tomcat为什么需要本机库性能与原理2.1 从Java NIO到APR连接器工作方式对比Tomcat从6.x版本开始引入APR连接器到8.5版本后经历了一次重要变化默认的HTTP连接器协议实现从BIO彻底切换到了NIO而APR变成了一个可选的增强项不再作为默认协议。这个变化让很多运维人员产生了困惑既然NIO已经是默认的APR还有必要单独装吗有必要。NIO和APR解决的不是同一个层面的问题。NIO解决的是“Java线程模型下的IO事件驱动问题”通过多路复用机制减少线程等待APR解决的是“跨平台底层I/O能力优化问题”利用操作系统原生的高性能能力两者是可以叠加的。也就是说即使Tomcat默认使用NIO模式只要APR库存在且配置了AprProtocolTomcat就会在NIO基础上进一步利用本地库能力。Tomcat 8.5及之后版本中Connector的protocol配置有三种常见选择protocol配置执行方式适用场景HTTP/1.1Java NIO通用场景默认配置org.apache.coyote.http11.Http11AprProtocolAPR/Native生产高并发、HTTPS、静态资源密集org.apache.coyote.http11.Http11Nio2ProtocolJava NIO.2需要异步IO特性的Java场景我在生产环境推荐的方式是NIO作为基础兜底APR作为性能增强。就算APR加载失败Tomcat也能正常运行不会出现雪崩一旦加载成功整个服务就在更优的执行路径上。2.2 什么场景必须处理这个告警判断要不要处理可以从三个维度看。第一个维度环境类型。本地开发、测试环境的Tomcat这个提示可以直接不管。但生产环境建议处理理由不是“告警看得烦”而是生产环境的多余资源消耗属于实打实的成本。公司如果接了APM监控某些指标确实能看出差别。第二个维度数据指标。如果你的项目有大量静态资源请求比如图片、CSS、JS、下载文件或者接口是短平快的小请求居多APR带来的系统调用优化收益非常明显。我有一台机器处理文件预览服务压测时QPS差别约在10%到20%之间虽然没有部分宣传里说的那么夸张但已经足够有动力去处理了。第三个维度SSL场景。项目用HTTPS访问且证书验证、握手频繁用APR直接调用OpenSSL进行握手比纯Java实现更快。遇到高并发短连接的API网关和统一认证服务时性能差距能被明显感知到。确认这三点之后再决定直接忽略告警还是彻底修复思路就清晰了。3. 解决方案实操从“忽略”到“彻底修复”3.1 第一步先判断你的Tomcat是否真的需要APR动手之前先想清楚顺序别颠倒。很多人在服务器上看了日志就直接开始编译安装最后发现这个项目根本不走APR协议白白折腾了一下午。判断方式是看你的server.xml里Connector的protocol配置。打开$CATALINA_HOME/conf/server.xml找到类似这样的节点Connector port8080 protocolHTTP/1.1 connectionTimeout20000 redirectPort8443 /如果protocol保持HTTP/1.1就表示当前走的是默认NIO模式即使不装APR库运行也完全正常。这个报错就属于“可选优化项未开启”不影响业务。如果你看到protocol是org.apache.coyote.http11.Http11AprProtocol或者APR的字样说明项目明确依赖APR能力。这时报错就不能忽略了必须安装本机库否则Connector初始化会失败严重情况下服务根本无法启动。还有一种情况项目用的是Spring Boot内嵌Tomcat。内嵌Tomcat默认也不配置APR协议日志里这类提示可以直接忽略。3.2 Windows环境安装Tomcat Native完整步骤如果判断后确定需要处理Windows环境下安装tc-native是最省事的。Windows下的Tomcat Native本质是一个DLL库主要文件是tcnative-1.dll如果使用Tomcat 10/11对应的是tcnative-2.dll。它运行依赖几个APR相关的DLL包括libapr-1.dll、libapriconv-1.dll、libaprutil-1.dll以及OpenSSL运行库所以不能光下载一个tcnative文件就完事。推荐的做法是去Apache Tomcat官网的Tomcat Native子页下载对应Windows安装包。下载后解压能看到完整的目录结构包含bin目录和lib目录。具体操作步骤将tcnative-1.dll复制到$CATALINA_HOME/bin目录下将依赖的DLL文件一并复制到bin目录或者放到系统PATH能识别的位置如果之前没有装过Visual C Redistributable运行库先安装对应版本否则加载时会提示缺少vcruntime140.dll之类的错误重启Tomcat观察日志是否出现Loaded APR based Apache Tomcat Native library字样。我的经验是Windows下最容易翻车的不是放置DLL而是32位和64位不匹配。注意你的JDK是64位就一定要用64位版本的本机库否则日志会直接报Unable to load library排查半天才发现是架构不一致。3.3 Linux环境编译安装APR与Tomcat NativeLinux环境是生产服务器的主流处理方式通常有两种包管理器安装和源码编译安装。先讲我最推荐的生产实践也就是编译安装过程可回溯、可控性强。首先安装编译依赖工具。CentOS/RHEL系执行yum install -y gcc make openssl-devel libtool autoconfUbuntu/Debian系执行apt-get update apt-get install -y gcc make libssl-dev libtool autoconf然后下载APR和APR-util源码。注意这里的APR不是Tomcat Native本身而是它依赖的底层库。从Apache官网下载源码包cd /usr/local/src wget https://archive.apache.org/dist/apr/apr-1.7.0.tar.gz wget https://archive.apache.org/dist/apr/apr-util-1.6.1.tar.gz tar -zxf apr-1.7.0.tar.gz cd apr-1.7.0 ./configure --prefix/usr/local/apr make make install cd /usr/local/src tar -zxf apr-util-1.6.1.tar.gz cd apr-util-1.6.1 ./configure --prefix/usr/local/apr --with-apr/usr/local/apr make make install接下来编译Tomcat Native。注意Tomcat Native版本要与Tomcat主版本匹配如果不确定就用Tomcat官网页面提供的当前版本。以Tomcat Native 2.0.6为例cd /usr/local/src wget https://dlcdn.apache.org/tomcat/tomcat-connectors/native/2.0.6/source/tomcat-native-2.0.6-src.tar.gz tar -zxf tomcat-native-2.0.6-src.tar.gz cd tomcat-native-2.0.6-src/native ./configure --with-apr/usr/local/apr --with-sslyes --prefix/usr/local/tomcat-native make make install编译完成后/usr/local/tomcat-native/lib目录下会生成libtcnative-1.so或libtcnative-2.so。这时还差最后一步告诉JVM去哪里找这个库文件。3.4 配置环境变量与启动参数这一步非常关键很多人在前一步编译成功后就以为大功告成结果重启Tomcat发现日志还在告警就是忘了配置加载路径。在Tomcat的bin目录下新建一个setenv.sh脚本如果系统里已经存在就直接编辑写入以下内容export LD_LIBRARY_PATH/usr/local/tomcat-native/lib:$LD_LIBRARY_PATH有了setenv.shTomcat的启动脚本catalina.sh会自动加载它比手动改catalina.sh更安全后续升级Tomcat版本也不会被覆盖。如果你不想通过环境变量方式也可以把本机库路径加到JVM启动参数里在setenv.sh中增加CATALINA_OPTS-Djava.library.path/usr/local/tomcat-native/lib:$CATALINA_OPTS两种方式二选一即可我个人的习惯是配置LD_LIBRARY_PATH形式更直观排错时也容易找到配置位置。保存后重启Tomcat观察日志。如果出现信息: Loaded APR based Apache Tomcat Native library [2.0.6] using APR version [1.7.0].说明加载成功告警消失。另外如果你的server.xml中Connector协议是默认的HTTP/1.1即使APR加载成功也需要显式指定APR协议才能获得最大化收益。Tomcat 8.5之后建议把protocol改成Connector port8080 protocolorg.apache.coyote.http11.Http11AprProtocol connectionTimeout20000 redirectPort8443 /改完之后重启Tomcat的HTTP连接器就会切到APR执行路径。这里有个需要注意的地方改协议之前一定要确保tc-native已经加载成功否则Connector会初始化失败。3.5 用包管理器安装的快捷方案如果你的服务器系统比较新也可以通过包管理器直接安装tc-native省去源码编译过程。CentOS/RHEL系yum install -y tomcat-nativeUbuntu/Debian系apt-get install -y libtcnative-1安装完成后库文件会被放在系统的标准库目录下比如/usr/lib/x86_64-linux-gnu理论上JVM默认的java.library.path就能找到不需要额外配置环境变量。但包管理器安装有一个隐藏风险版本通常和Tomcat官方最新版存在差距。如果你的Tomcat是10.x或11.x而系统的libtcnative还是老的1.2.x加载时会出现版本不兼容的问题。我的建议是固态的、跟随Tomcat官方更新的环境用源码编译追求快速、能用就行的环境用包管理器。4. 常见坑点与排查技巧实录4.1 版本不匹配Tomcat Native 1.x和2.x的区别这是最高频的翻车点需要单独拿出来说。Tomcat Native库版本与Tomcat主版本有对应关系Tomcat版本对应Native库典型库文件名Tomcat 7/8/91.2.xtcnative-1.dll / libtcnative-1.soTomcat 10/10.1/112.xtcnative-2.dll / libtcnative-2.so如果你用Tomcat 10去加载1.2版本的库启动时会看到类似The Tomcat Native library failed to load的附加错误有时还会抛NoClassDefFoundError。因为Tomcat 10升级到Jakarta EE命名空间本地库也做了同步更新老的库无法识别新版本内部接口。遇到这种情况不要纠结直接下载对应版本的tc-native重装。版本号可以在Tomcat官网的Tomcat Connectors目录下看到需要区分native/2.x和native/1.2.x两个不同的下载入口。4.2 OpenSSL版本与编译器兼容性Linux下编译安装tc-native时OpenSSL版本不匹配是仅次于版本匹配的第二大坑。高版本OpenSSL对内存分配、线程安全有新的要求老版本的tcnative在加载时可能直接崩溃或抛出UnsatisfiedLinkError。我遇到过这样一个案例某台机器原本跑得好好的tc-native加载正常但在运维统一升级了系统的OpenSSL之后Tomcat启动时APR突然加载失败日志中没有任何明确的堆栈信息。排查半天才发现是OpenSSL版本升级后老版本的tcnative链接到了旧的OpenSSL符号表加载时找不到对应函数。解决方式很明确升级Tomcat Native版本重新编译链接到当前系统的OpenSSL版本。编译时--with-sslyes会自动探测OpenSSL路径如果探头失败需要手动指定./configure --with-apr/usr/local/apr --with-ssl/usr/bin/openssl --prefix/usr/local/tomcat-native但如果是系统从OpenSSL 1.0升级到1.1或者3.x这类大版本变更建议直接系统升级后重装tc-native只改编译参数解决不了根本问题。4.3 日志里还有其他报错怎么排查有时候日志里除了“not found”之外还会出现其他附加错误比如信息: The APR based Apache Tomcat Native library failed to load. java.lang.UnsatisfiedLinkError: no tcnative-1 in java.library.path这种报错说明Tomcat虽然发动了寻找过程但找到一个不可用的文件或者文件本身无法被加载。排查思路按三步走。第一步确认库文件是否真的存在ls -l /usr/local/tomcat-native/lib/第二步确认动态链接依赖是否完整用ldd检查ldd /usr/local/tomcat-native/lib/libtcnative-1.so如果有依赖显示not found说明系统里缺某个基础运行库常见的是libapr-1.so.0、libssl.so等。这时先把缺的库装上再重启Tomcat。第三步确认运行Tomcat的系统用户比如tomcat用户是否有权限读取这个目录。如果tomcat用户没有/usr/local/tomcat-native目录的执行权限也会导致加载失败。另外还有一类问题虽然不报”not found“但会让你困惑tomcat的单独启动脚本不能加载LD_LIBRARY_PATH比如用systemd管理Tomcat时。systemd的service文件里环境变量通常需要额外指定光写setenv.sh是不够用的需要在service文件中增加EnvironmentLD_LIBRARY_PATH/usr/local/tomcat-native/lib否则明明在终端下启动正常用systemd启动就会找不到库。这个坑也踩过的人不少。4.4 排查技巧速查表为了方便现场操作我把常见的报错现象和排查方向整理成一个速查表启动日志现象可能原因优先排查方向提示not found项目正常启动APR未安装需判断是否启用APR协议server.xml中的protocol配置提示failed to load伴随UnsatisfiedLinkError库文件不可用架构或依赖缺失ldd检查动态库依赖提示loaded但Connector仍用NIOserver.xml未配置APR协议检查Connector的protocol属性提示loaded但启动后访问404项目部署或路径问题与APR无关单独排查web应用的上下文路径提示版本号不对tc-native版本与Tomcat主版本不匹配下载匹配版本的tc-native有些“坑”其实和APR无关别被带偏了方向。5. 处理完告警之后的验证与效果观察5.1 如何确认APR真的生效了看到日志输出Loaded APR based Apache Tomcat Native library只是第一步真正要确认的是Tomcat的Connector确实跑在APR路径上。可以通过ps -ef | grep tomcat确认Tomcat进程在运行后再访问Tomcat的状态页面。如果你在server.xml中配置了Manager或Host Manager可以进入http://ip:8080/manager/status查看连接器信息。如果没开管理页面可以通过JMX或者直接看日志确认。更直接的办法是用lsof检查Tomcat进程是否加载了tcnativelsof -p $(pgrep -f org.apache.catalina.startup.Bootstrap) | grep tcnative如果能搜到libtcnative-X.so的记录说明库文件被进程真实加载不是日志误报。还有一种验证方式是从指标层面看。处理完APR后再做一次简单的压测对比比如用ab或wrk工具对同一个静态文件路径发起请求对比安装前后的QPS和平均响应时间。APR在keep-alive连接下的效果尤其明显如果压测数据没有提升先别急着怀疑安装过程优先检查是否真的启用了AprProtocol。5.2 观察指标有哪些参考价值不同的业务场景APR带来的收益体现也不一样。我这里给出几个常见场景的参考口径场景主要观察指标预期变化趋势静态文件下载吞吐量、网络IOQPS提高CPU占用下降HTTPS短连接TLS握手耗时、连接建立耗时平均响应时间下降高并发小请求线程数、等待队列长度线程数占用减少队列堆积变短文件上传下载内存占用、垃圾回收频率GC压力降低内存占用更平稳我自己的经验是不要在刚处理完后就立刻下结论多观察几天结合APM平台的长期趋势判断。APR不是银弹有些场景提升没那么明显但只要生产环境能用上原生IO能力本质上就是一种“提前投资”后续流量增长时不用再回头折腾基础层。6. 最后再分享几个实际运维中的心得处理“找不到基于APR的Apache Tomcat本机库”这个问题说起来是一个很具体的启动告警但做起来牵扯到Tomcat运行模式、JVM类库加载、操作系统动态库依赖等多个层面。我在几次部署和排障中积累了一些自己的经验挑几个值得说的讲讲。第一个心得是别一上来就开刀先做评估。遇到这个告警首先看环境是开发还是生产看项目是否需要APR特性。很多开发同学把大量精力花在这上面其实重点应该是业务功能本身。判断标准很简单如果页面访问正常、接口响应正常开发环境完全不用处理。第二个心得是生产环境安装APR时一定要做完整的验证闭环。安装完成后不只是看日志要确认Connector协议配置、验证库文件被进程加载、观察一段时间指标。闭环验证能避免“看似解决了实际上还在NIO模式跑”的假成功情况。第三个心得是系统升级后要重新检查APR状态。操作系统做安全补丁升级尤其是OpenSSL、glibc相关组件的升级有可能会影响tc-native的加载。生产环境升级系统组件后我建议把Tomcat重启一次再确认启动日志防患于未然。还有一个很多人不知道的小技巧如果你的服务器上同时装多个版本的JDK记得确认Tomcat用的是哪个JDK。因为java.library.path中包含的路径和JDK安装位置强相关不同JDK版本的默认搜索路径差异不小有时候明明库文件就在那里换一个JDK启动就找不到了。我这套流程走下来基本能把“找不到基于APR的Apache Tomcat本机库”这个问题彻底解决而且对项目后续的性能优化也有帮助。如果你在生产环境处理完这个告警后再配合JVM参数调优和连接器参数调整整个Tomcat的运行效率还能再上一个台阶。
返回列表