【发布时间】:2012-12-21 11:44:14
【问题描述】:
在我们的生产环境中,我们时常会在Tomcat中遇到一个非常奇怪的编码问题。
我还不能确定问题发生在代码中的确切位置,但它涉及将非 ascii 字符替换为近似的 ascii 字符。
例如将字符 'å' 替换为 'a'。由于该站点是瑞典语,因此字符“å”、“ä”和“ö”很常见。但是由于某种原因,替换 'ö' 字符总是有效的,所以像“Köp inte grisen i säcken”这样的字符串变成了“Kop inte grisen i säcken”,即 'ä' 没有被替换,而 ' ö' 字符是。
关于这个问题的一些简单的事实:
这种情况很少发生(我们注意到它 3-4 次,第一次可能是 1-2 年前)。
重启有问题的服务器可以解决问题(直到下一次)。
从未在超过一台前端服务器上同时发生过。
它并不总是发生在同一个前端服务器上。
不涉及前端的用户输入。
所有前端服务器都连接到同一个 CMS 和 DB,相关配置相同。
所有前端服务器都具有相同的相关配置(linux 配置、tomcat 配置、java 环境配置,如“file.encoding”等),并使用相同的脚本启动(全部根据托管/服务提供商)。
所有前端服务器都使用相同的站点战争文件和相同的 jar 文件。
出现此字符替换问题时,站点上没有其他编码问题。
我们从未能够在任何其他环境中重现此问题。
由于 CMS 要求,我们使用 Tomcat 5.5 和 Java 5。
对于这种行为,我只能想到两个可能的原因:
托管服务提供商有时会以不同的方式启动/重新启动前端服务器,可能使用具有其他环境变量或其他文件访问权限的另一个用户帐户,或者可能使用不同于正常脚本的其他脚本。
-
在 Tomcat 或 webapp 启动期间运行的某些进程依赖于其他进程,有时(间歇性但很少)这两个(或更多)进程碰巧按导致此编码缺陷的顺序运行。
但是即使上面的 1 或 2 是这种情况,它仍然不能完全解释真正发生的事情。有什么确切的区别可以解释这一点?由于所有“file.encoding”、“file.encoding.pkg”、“sun.io.unicode.encoding”、“sun.jnu.encoding”和所有其他相关环境变量在所有前端机器上都匹配(使用目视验证调试页面,而问题正在发生)。
对于这种奇怪的间歇性行为,有人能想出一些合理的解释吗?简单地升级 Tomcat 和/或 Java 版本并不是一个真正相关的答案,因为我们真的不知道这是否会解决问题,它仍然不能解释问题是什么。我更感兴趣的是确切地了解问题是由什么引起的。
问候 /吉米
更新:
我想我找到了执行字符替换的代码。在初始化时(由第一次调用来进行替换)它构建一个 HashMap
lookup.put(new Character('å'), "a");
然后当它应该替换字符串的字符时,它会遍历每个字符,并以字符为键在哈希映射中查找每个字符,如果找到替换字符串,则使用它,否则原始使用字符。
这部分代码已经有 3 年多的历史了,并且是由一个早已不复存在的开发人员编写的。如果我今天重写这段代码,我会做一些完全不同的事情,这甚至可以解决问题。但它仍然无法准确解释发生了什么。有人能看到一些可能的解释吗?
【问题讨论】:
-
听起来像是一个多线程问题,有些不是线程安全的操作。我见过类似的问题,每隔几周就会发生一次错误转换。原因始终是对共享数据的非线程安全访问。尝试给机器增加一些非常重的负载,强制进行大量并行字符转换,看看会发生什么。
-
问题是一旦服务器进入这种麻烦的模式,所有这些操作都会以同样的错误方式结束,每次都以相同的方式结束,直到服务器重新启动。因此,如果多线程是原因,您认为它到底触发了什么?此外,让生产前端承受重负载会对网站访问者产生负面影响,这不是我们愿意做的事情。
-
在不知道代码的情况下,几乎不可能说出来。尝试隔离转换例程并在繁重的多线程环境中运行它们。
-
我刚刚用一些代码更新了这个问题。假期后可能有时间做一些本地多线程测试,尽管我仍然不相信这到底是怎么造成的。对此有何理论解释?
标签: java tomcat encoding character intermittent