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乱码的更多相关文章

  1. Java file.encoding

    1. file.encoding属性的作用 file.encoding 的值是整个程序使用的编码格式. 可以使用  System.out.println(System.getProperty(&quo ...

  2. file.encoding到底指的是什么呢?

    转载请注明来源:http://blog.csdn.net/loongshawn/article/details/50918506 <Java利用System.getProperty(“file. ...

  3. 系统变量file.encoding对Java的运行影响有多大?(转)good

    这个话题来自: Nutz的issue 361 在考虑这个issue时, 我一直倾向于使用系统变量file.encoding来改变JVM的默认编码. 今天,我想到, 这个系统变量,对JVM的影响到底有多 ...

  4. Flume+Kafka+Storm+Hbase+HDSF+Poi整合

    Flume+Kafka+Storm+Hbase+HDSF+Poi整合 需求: 针对一个网站,我们需要根据用户的行为记录日志信息,分析对我们有用的数据. 举例:这个网站www.hongten.com(当 ...

  5. kafka+storm+hbase

    kafka+storm+hbase实现计算WordCount. (1)表名:wc (2)列族:result (3)RowKey:word (4)Field:count 1.解决: (1)第一步:首先准 ...

  6. eclipse的使用-------Text File Encoding没有GBK选项的设置

    eclipse的使用-------Text File Encoding没有GBK选项的设置 2013-12-25 09:48:06 标签:java myeclipse使用 有一个项目是使用GBK编码的 ...

  7. readAsDataURL(file) & readAsText(file, encoding)

      readAsDataURL(file)会把文件内容转换为data类型的URL: data:text/plain;base64,b3JkZXItaWQJb3JkZXItaXRlbS1p... 这种d ...

  8. Storm+HBase实时实践

    1.HBase Increment计数器 hbase counter的原理: read+count+write,正好完成,就是讲key的value读出,若存在,则完成累加,再写入,若不存在,则按&qu ...

  9. Android studio 配置file encoding 无效,中文乱码解决办法

    通过配置Android studio 配置file encoding 无效,中文乱码,问题出现在java编译的时候jack采用了默认编码(中文windows默认的GBK编码)而乱码,所以不管更改bui ...

随机推荐

  1. 微信开源组件WCDB漫谈及Demo

    代码地址如下:http://www.demodashi.com/demo/12422.html 前言 移动端的数据库选型一直是一个难题,直到前段时间看到了WeMobileDev(微信前端团队)放出了第 ...

  2. xshell的快捷键(很有用)

    删除 ctrl + d      删除光标所在位置上的字符相当于VIM里x或者dl ctrl + h      删除光标所在位置前的字符相当于VIM里hx或者dh ctrl + k      删除光标 ...

  3. Jconsole 工具介绍和使用方法

    http://chain.blog.163.com/blog/static/14084852320117934024410/ JConsole是一个基于JMX的GUI工具,JDK自带小工具     h ...

  4. Bootstrap学习速查表(三) 表单

    表单中常见的元素主要包括:文本输入框.下拉选择框.单选按钮.复选按钮.文本域和按钮等. 一.基础表单 1.初始化:对于基础表单,Bootstrap并未对其做太多的定制性效果设计,仅仅对表单内的fiel ...

  5. 宜信开源|微服务任务调度平台SIA-TASK入手实践

    引言 最近宜信开源微服务任务调度平台SIA-TASK,SIA-TASK属于分布式的任务调度平台,使用起来简单方便,非常容易入手,部署搭建好SIA-TASK任务调度平台之后,编写TASK后配置JOB进行 ...

  6. 一条长l的笔直的街道上有n个路灯,若这条街的起点为0,终点为l,第i个路灯坐标为ai,每盏灯可以覆盖到的最远距离为d,为了照明需求,所有灯的灯光必须覆盖整条街,但是为了省电,要是这个d最小,请找到这个最小的d。

    // ConsoleApplication3.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> ...

  7. InputFormat的认识

    InputFormat 负责处理MR的输入部分. 有三个作用: 一.验证作业的输入是否规范. 二.把输入文件切分成InputSplit. 三.提供RecordReader 的实现类,把InputSpl ...

  8. 理解cas

    前言 CAS(Compare and Swap),即比较并替换,实现并发算法时常用到的一种技术,Doug lea大神在java同步器中大量使用了CAS技术,鬼斧神工的实现了多线程执行的安全性. CAS ...

  9. PHP合并数组+与array_merge的区别

    http://www.phpernote.com/php-string/351.html PHP中合并两个数组可以使用+或者array_merge,但这两个还是有区别的   主要区别是当两个或者多个数 ...

  10. android 自定图库(转)

    githup: https://github.com/pengjianbo/GalleryFinal GalleryFinal简介 Android自定义相册,实现了拍照.图片选择(单选/多选). 裁剪 ...