這篇文章主要介紹“jvm file.encoding屬性引起的HBase亂碼問題怎么解決”,在日常操作中,相信很多人在jvm file.encoding屬性引起的HBase亂碼問題怎么解決問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”jvm file.encoding屬性引起的HBase亂碼問題怎么解決”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
目前創(chuàng)新互聯(lián)建站已為上千的企業(yè)提供了網(wǎng)站建設、域名、虛擬空間、網(wǎng)站運營、企業(yè)網(wǎng)站設計、舒蘭網(wǎng)站維護等服務,公司將堅持客戶導向、應用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。
最近在往 HBase 寫中文的時候,發(fā)現(xiàn) hbase 查出來的數(shù)據(jù)會有部分中文亂碼了,而部分中文又是正常的,按理來說,一般的亂碼問題要么全亂,要么不亂??紤]到出現(xiàn)中文的地方都是來源于 hdfs 上的一個配置文件,而這個配置文件可以確定是 utf-8 編碼的,那排除了原始文件導致的亂碼,想想 MR 代碼里也沒有轉(zhuǎn)碼的邏輯,也排除了代碼的問題,那就只有一種可能:Hadoop 集群的系統(tǒng)環(huán)境是異構的,這里面可能涉及到 linux 、java 的環(huán)境變量、配置的問題。
(1)打印了整個集群的 echo $LANG、echo $LC_ALL 等linux系統(tǒng)變量,發(fā)現(xiàn)都是一致的,排除了 os 環(huán)境的問題。
(2)剩下的重點放在了 java 環(huán)境上,在代碼里加上如下兩句,打印每條記錄的 ip 和 jvm 編碼,然后看看亂碼的記錄是那臺機器產(chǎn)生的,并且當時 jvm child 的編碼情況:
java.net.InetAddress test = java.net.InetAddress.getByName("localhost"); put.add(Bytes.toBytes("cf"), Bytes.toBytes("ip"), Bytes.toBytes(test.getLocalHost().getHostAddress())); put.add(Bytes.toBytes("cf"), Bytes.toBytes("ec"), Bytes.toBytes(System.getProperty("file.encoding")));
同時也直接 System.out.println 出相應的中文字段,看是寫進 hbase 之前還是之后亂掉的。
跑了一份測試數(shù)據(jù)后,發(fā)現(xiàn) hbase 里的 ip、jvm 編碼是沒有規(guī)律的,然后查看 syso 打印的 log 發(fā)現(xiàn),在寫 hbase 之前已經(jīng)就已經(jīng)亂碼了,然后想想 hbase 里的數(shù)據(jù)亂碼之所以沒有規(guī)律是因為 map 后要 shuffle、reduce 才能到 hbase。PS:sysout本身無編碼概念,類似 linux 下的 cat、head、more 等。
然后再次把 ip、jvm編碼 統(tǒng)計代碼放到 map 階段輸出,果真發(fā)現(xiàn)了規(guī)律,集群中有兩臺機器的 jvm 編碼不一致,不是 utf-8 的:
到這里我們可以知道原因了:由于集群中兩臺機器的 jvm 參數(shù)(file.encoding)不一致導致了部分中文結果的亂碼。
知道原因了,那就看如何解決了,目的就是要改變 file.encoding 的值 。
由于這個參數(shù)是 jvm 的啟動參數(shù),運行時不可被更改(你可以理解為這個參數(shù)是個全局參數(shù),而且被緩存了,如果一旦運行時更改了, 可能會造成整個 jvm 里面的程序奔潰),你只能修改系統(tǒng)的charset, 或者jvm的啟動參數(shù)里加上 -Dfile.encoding="UTF-8">,你運行時 setProperty("file.encoding","ISO-8859-1"); 這樣是沒用的,so,永久的解決辦法是:啥時候把這兩臺機器offline 改編碼后再online,然后再手動執(zhí)行下 data balance。
或者可以在提交作業(yè)的時候設置作業(yè)參數(shù): –Dmapred.child.env="LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8"
不想這么大動干戈,想要臨時解決方案,也行,那就需要在咱們自己的業(yè)務代碼里繞開 jvm 提供的默認 file.encoding 編碼,自己指定編碼:
BufferedReader in = new BufferedReader(new FileReader(path.toString())); 換成: BufferedReader in = new BufferedReader((new InputStreamReader(new FileInputStream(path.toString()),"utf-8")));
上面一句是我之前亂碼的代碼,如果你沒有指定讀取編碼,那么 jvm 會使用自己的 file.encoding,這樣就會造成在某些機器上讀取文件就亂掉了。下面一句是自己指定編碼,這樣繞開了 jvm 的默認編碼,與 jvm 從此形同陌路~
PS:FileReader 貌似沒有提供指定編碼的構造方法,所以換成了下面的類。
為什么之前一直都沒亂碼,而這次讀文件卻亂碼了呢?
那是因為 hbase 的 Bytes、map 的 fileinputformat key/value、mapreduce 的 context.write 默認都是自己硬編碼了 utf-8,做到了 和 jvm 編碼無關,所以不會遇到上述問題。
上面說了這么多,可能有同學還是不大明白:jvm 的這參數(shù)有毛用啊?為毛之前都沒聽過這玩意呢?
恩,沒聽過正常,之前我也沒聽過哈~
在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), 都會調(diào)用Charset.defaultCharset()的方法,我們可以清楚的看到defaultCharset是只能被初始化一次,這里還是有點小問題的,在多線程并發(fā)調(diào)用的時候還是會初始話多次,當然后面都是從cache(lookup的函數(shù))里讀出來的,問題也不大。
當我們在改變System.getProperties里的file.encoding 的時候,defaultCharset已經(jīng)被初始化過了,所以不會在調(diào)用初始化的代碼。
當jvm 啟動的時候,load class, 最后調(diào)用main函數(shù)之前,defaultCharset已經(jīng)初始化好,而很多函數(shù)里都掉用了這個方法象String.getBytes, 還有 InputStreamReader, InputStreamWriter 都是調(diào)用了 Charset.defaultCharset()的方法。
(b)java.net.URLEncoder的靜態(tài)構造方法, 影響到的方法 java.net.URLEncoder.encode(String)
恩,這里也需要注意,之前已經(jīng)有同學掉坑里去了,請使用:encode(String s, String enc) 方法,此法無側(cè)漏,一覺睡到大天亮~
(c)com.sun.org.apache.xml.internal.serializer.Encoding的getMimeEncoding方法(209行起)
(d)最后一個javax.print.DocFlavor類的靜態(tài)構造方法
可以看到,系統(tǒng)變量file.encoding影響到
1. Charset.defaultCharset() Java環(huán)境中最關鍵的編碼設置
2. URLEncoder.encode(String) Web環(huán)境中最常遇到的編碼使用
3. com.sun.org.apache.xml.internal.serializer.Encoding 影響對無編碼設置的xml文件的讀取
4. javax.print.DocFlavor 影響打印的編碼
到此,關于“jvm file.encoding屬性引起的HBase亂碼問題怎么解決”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關知識,請繼續(xù)關注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
分享標題:jvmfile.encoding屬性引起的HBase亂碼問題怎么解決
URL地址:http://jinyejixie.com/article42/jjigec.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站制作、App設計、小程序開發(fā)、網(wǎng)站收錄、網(wǎng)站導航、響應式網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)