jvm file.encoding 属性引起的storm/hbase乱码
1. 问题
今天为storm程序添加了一个计算bolt,上线后正常,结果发现之前的另一个bolt在将中文插入到hbase中后查询出来乱码。其中字符串是以UTF-8编码的url加密串,然后我使用的URLDecoder.decode(str, "UTF-8")解码,最后插入到hbase中。
2. 排查
(1)hbase中的数据传输都是使用的UTF-8,因此肯定不会出问题,故排除hbase端的问题;
(2)既然在测试的时候没乱码,线上却乱码,想到肯定是线上机子jvm环境的问题;
(3)确定了是jvm环境的问题,再一想URLDecoder.decode(str, "UTF-8")这句解码肯定用的是UTF-8,如果str编码是UTF-8的解出来当然就不会乱了,于是明确str在jvm中被用非UTF-8编码了;
(4)排查线上那台机子的jvm默认编码
首先,打印了 echo $LANG、echo $LC_ALL 等linux系统变量,发现都是一致的UTF-8,排除了 os 环境的问题。
然后,重点放在了 java 环境上,使用System.getProperty(
"file.encoding"
);打印jvm的默认编码,结果出来的是:ISO-8859-1。
到这里我们可以知道原因了:由于线上那台机子的 jvm 参数(file.encoding)不一致导致了中文的乱码。
3. 解决方案
知道原因了,解决起来就简单了,目标就是改变JVM file.encoding参数的值。
由于这个参数是jvm的启动参数,运行时不可更改(你可以理解为这个参数是个全局参数,而且被缓存了,如果一旦运行时更改了, 可能会造成整个 jvm 里面的程序奔溃)。
(1)临时方案
jvm的启动参数里加上-Dfile.encoding="UTF-8"来指定。
(2)一劳永逸方案
修改系统的charset,linux的字符集在/etc/sysconfig/i18n文件中设置,下面是我的机子默认设置:
LANG="en_US"
SYSFONT="latarcyrheb-sun16"
有两种修改方式:1.将/etc/sysconfig/i18n中的LANG修改为LANG="en_US.UTF-8",修改后需要重启机子才能生效;2.在/etc/profile中添加export LANG=en_US.UTF-8,然后source /etc/profile即可生效。
4. 疑问
为何之前这个bolt一直正常?因为storm对bolt的分配是自己控制的(对用户而言相当于随机分配到不同的节点),之前这个bolt分配到的那个机子的jvm编码设置的为en_US.UTF-8,故不会出现问题。
5. 深入理解 jvm 的 -Dfile.encoding 参数
上面说了这么多,可能有同学还是不大明白:jvm 的这参数有啥用啊?为啥之前都没听过这玩意呢?恩,没听过正常,之前我也没听过哈~
(1) JVM编码原理
jvm内部的(字节码)编码方式为unicode,编码和解码过程为:(1)编码:首先将字符串使用jvm默认的编码方式(也可以手动指定)转换为unicode存储到内存中;(2)解码:然后就unicode编码的字符串解码为用户指定的编码字符串。因此,只要保证编码和解码两端的字符集编码方式一致就不会出现乱码。
(2)查询源码
在JDK 1.6.0_20的src.zip文件中,查找包含file.encoding字眼的文件,共找到4个:
(a)先上重头戏 java.nio.Charset类:
public static Charset defaultCharset() {
if (defaultCharset == null) {
synchronized (Charset.class) {
java.security.PrivilegedAction pa = new GetPropertyAction("file.encoding");
String csn = (String) AccessController.doPrivileged(pa);
Charset cs = lookup(csn);
if (cs != null)
defaultCharset = cs;
else
defaultCharset = forName("UTF-8");
}
}
return defaultCharset;
}
在java中,如果没有指定charset的时候,比如new String(byte[] bytes), 都会调用Charset.defaultCharset()的方法,我们可以清楚的看到defaultCharset是只能被初始化一次,这里还是有点小问题的,在多线程并发调用的时候还是会初始话多次,当然后面都是从cache(lookup的函数)里读出来的,问题也不大。
当我们在改变System.getProperties里的file.encoding 的时候,defaultCharset已经被初始化过了,所以不会在调用初始化的代码。
当jvm 启动的时候,load class, 最后调用main函数之前,defaultCharset已经初始化好,而很多函数里都掉用了这个方法象String.getBytes, 还有 InputStreamReader, InputStreamWriter 都是调用了 Charset.defaultCharset()的方法。
(b)java.net.URLEncoder的静态方法, 影响到的方法 java.net.URLEncoder.encode(String)
恩,这里也需要注意,之前已经有同学掉坑里去了,请使用:encode(String s, String enc) 方法
(c)com.sun.org.apache.xml.internal.serializer.Encoding的getMimeEncoding方法(209行起)
(d)最后一个javax.print.DocFlavor类的静态构造方法
可以看到,系统变量file.encoding影响到
1. Charset.defaultCharset() Java环境中最关键的编码设置
2. URLEncoder.encode(String) Web环境中最常遇到的编码使用
3. com.sun.org.apache.xml.internal.serializer.Encoding 影响对无编码设置的xml文件的读取
4. javax.print.DocFlavor 影响打印的编码
(3)Java's file.encoding property on Windows platform
This property is used for the default encoding in Java, all readers and writers would default to use this property. “file.encoding” is set to the default locale of Windows operationg system since Java 1.4.2. System.getProperty(“file.encoding”) can be used to access this property. Code such as System.setProperty(“file.encoding”, “UTF-8”) can be used to change this property. However, the default encoding can not be changed dynamically even this property can be changed. So the conclusion is that the default encoding can’t be changed after JVM starts. “java -Dfile.encoding=UTF-8” can be used to set the default encoding when starting a JVM. I have searched for this option Java official documentation. But I can’t find it.
5. 参考文章
(1)系统变量file.encoding对Java的运行影响有多大
http://www.blogjava.net/ivanwan/archive/2011/01/31/343810.html
(2)linux查看系统和修改系统编码
http://www.poluoluo.com/server/201401/258604.html
(3)en_US.UTF-8和zh_CN.UTF-8的区别
http://www.iteye.com/problems/90396
jvm file.encoding 属性引起的storm/hbase乱码的更多相关文章
- Java file.encoding
1. file.encoding属性的作用 file.encoding 的值是整个程序使用的编码格式. 可以使用 System.out.println(System.getProperty(&quo ...
- file.encoding到底指的是什么呢?
转载请注明来源:http://blog.csdn.net/loongshawn/article/details/50918506 <Java利用System.getProperty(“file. ...
- 系统变量file.encoding对Java的运行影响有多大?(转)good
这个话题来自: Nutz的issue 361 在考虑这个issue时, 我一直倾向于使用系统变量file.encoding来改变JVM的默认编码. 今天,我想到, 这个系统变量,对JVM的影响到底有多 ...
- Flume+Kafka+Storm+Hbase+HDSF+Poi整合
Flume+Kafka+Storm+Hbase+HDSF+Poi整合 需求: 针对一个网站,我们需要根据用户的行为记录日志信息,分析对我们有用的数据. 举例:这个网站www.hongten.com(当 ...
- kafka+storm+hbase
kafka+storm+hbase实现计算WordCount. (1)表名:wc (2)列族:result (3)RowKey:word (4)Field:count 1.解决: (1)第一步:首先准 ...
- eclipse的使用-------Text File Encoding没有GBK选项的设置
eclipse的使用-------Text File Encoding没有GBK选项的设置 2013-12-25 09:48:06 标签:java myeclipse使用 有一个项目是使用GBK编码的 ...
- readAsDataURL(file) & readAsText(file, encoding)
readAsDataURL(file)会把文件内容转换为data类型的URL: data:text/plain;base64,b3JkZXItaWQJb3JkZXItaXRlbS1p... 这种d ...
- Storm+HBase实时实践
1.HBase Increment计数器 hbase counter的原理: read+count+write,正好完成,就是讲key的value读出,若存在,则完成累加,再写入,若不存在,则按&qu ...
- Android studio 配置file encoding 无效,中文乱码解决办法
通过配置Android studio 配置file encoding 无效,中文乱码,问题出现在java编译的时候jack采用了默认编码(中文windows默认的GBK编码)而乱码,所以不管更改bui ...
随机推荐
- 在SAE安装原版WORDPRESS(图文讲解)
wordpress下载:https://cn.wordpress.org/ 在Sina App Engine上搭建WordPress博客图文教程: 一.登录你的SAE账号以后.进入"我的应用 ...
- css3动画学习资料整理
现在主流浏览器(先不管IE8,IE9吧),尤其是移动端浏览器基本都支持css3了,为了增强页面的表现力,css3动画必不可少了.这篇文章主要整理一下我在学习css3动画所查阅的一些好的资料,并附上两个 ...
- A008-drawable资源
关于drawable资源笔者之前有写过两篇文章: Android-自己定义图像资源的使用(1) Android-自己定义图像资源的使用(2) 这里笔者就不做过多的赘述.我们从实际开发的角度去理解这个知 ...
- 优志愿前端数据加密破解-python
# coding=utf-8 import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "etiaky.sett ...
- eclipse中三大利器
eclipse中两大利器: 首先说下用eclipse开发工具.进行java代码,开发的时候,我们开发完成以后.需要测试.大部分我们用Junit测试工具.可是内部的代码覆盖率.和结构我们看的不是那么详细 ...
- eclipse spring4 ehache2.10 整合
http://blog.csdn.net/tonytfjing/article/details/39251507 http://my.oschina.net/duoduo3369/blog/17392 ...
- VI使用说明 (转)
vi使用方法(ZT) vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令.由于对Unix及Lin ...
- mysql系列之9.mysql日志&存储引擎
mysqlbinlog 是什么? 数据目录下的如下文件: mysql-bin.xxxxxx 作用? 记录数据库内部增删改查对mysql数据库有更新的内容的记录 三种模式? statement leve ...
- SQL2005数据库放在C盘,结果C盘满了,怎么搞到D盘
首先,你需要将自己所建立的数据库从SQL2005中分离出来,然后按照自己的存储路径找到自己所建数据库存储的位置,把它剪切到D盘就可以了.(mdf,ldf都应该考过去,自己建立路径存储就可以,再次打开的 ...
- Android 破解
一.反编译 默认你的电脑中完好的有java环境 1.下载 Android killer 链接: https://pan.baidu.com/s/1s6lfm8CbdU9ABYEOhdFWxA 提取码 ...