自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

記錄一次 Hbase 線上問題的分析和解決

大數(shù)據(jù)
本篇文章,我們回顧一次 hbase 線上問題的分析和解決 - KeyValue size too large,總結(jié)下背后的知識(shí)點(diǎn),并分享一下查看開源組件不同版本差異點(diǎn)的方法。

[[439936]]

大家好,我是明哥!

本篇文章,我們回顧一次 hbase 線上問題的分析和解決 - KeyValue size too large,總結(jié)下背后的知識(shí)點(diǎn),并分享一下查看開源組件不同版本差異點(diǎn)的方法。

希望大家有所收獲,謝謝大家!

01 Hbase 簡介

Hbase 作為 hadoop database, 是一款開源,分布式易擴(kuò)展,面向大數(shù)據(jù)場景的,多版本,非關(guān)系型,數(shù)據(jù)庫管理系統(tǒng),是 Google Bigtable 的 JAVA 版開源實(shí)現(xiàn)。

Hbase 的底層存儲(chǔ)引擎是 HDFS,可以在普通商業(yè)級(jí)服務(wù)器硬件(即常說的 x86 架構(gòu)的服務(wù)器)的基礎(chǔ)上,提供對(duì)超大表(表的數(shù)據(jù)量可以有百萬行,每行的列數(shù)可以有百萬級(jí))的隨機(jī)實(shí)時(shí)讀寫訪問。

Hbase具有以下特征:

  • 模塊化的線性擴(kuò)展性;
  • 強(qiáng)一致性并發(fā)讀寫支持;
  • 可配置的表的自動(dòng) sharding;
  • 表分區(qū)在 RegionServer 間的自動(dòng) failover;
  • 基于 Block cache 和 Bloom 過濾器的實(shí)時(shí)讀取;
  • 基于 server 端過濾器的查詢謂詞下推;

正是因?yàn)?Hbase 的上述特征,Hbase 在各行各業(yè)有許多線上應(yīng)用案列,可以說是 NoSql 數(shù)據(jù)庫的一個(gè)典型代表:

  • 在各種超大數(shù)據(jù)量級(jí)
  • 在需要實(shí)時(shí)并發(fā)讀寫支持
  • 在表的結(jié)構(gòu)比較靈活(即有很多稀疏列:有很多行和很多列,但每一行只有眾多列中的少數(shù)列有值)
  • 筆者就在車聯(lián)網(wǎng)場景下重度使用過 Hbase

題外話:

Nosql 數(shù)據(jù)庫有幾大類,幾個(gè)典型代表是:Hbase, ElasticSearch, MongoDb;

有個(gè)有趣的現(xiàn)象,筆者發(fā)現(xiàn)國內(nèi) Hbase 使用的多,而國外似乎 Cassandra 使用的多。

02 一次線上 Hbase 問題的問題現(xiàn)象

某線上應(yīng)用使用了 Hive 到 Hbase 的映射表,在使用 insert overwrite 從 hive 表查詢數(shù)據(jù)并插入 HBASE 表時(shí),發(fā)生了錯(cuò)誤。

通過查看 HIVE 背后 YARN 上的作業(yè)的日志,發(fā)現(xiàn)主要錯(cuò)誤信息是 java.lang.IllegalArgumentException: KeyValue size too large,詳細(xì)報(bào)錯(cuò)截屏和日志如下:

  1. 2020-04-08 09:34:38,120 ERROR [main] ExecReducer: org.apache.hadoop.hive.ql.metadata.HiveException: Hive Runtime Error while processing row (tag=0) {"key":{"_col0":"0","_col1":"","_col2":"2020-04-08","_col3":"joyshebaoBeiJing","_col4":"105","_col5":"北京,"},"value":null
  2.     at org.apache.hadoop.hive.ql.exec.mr.ExecReducer.reduce(ExecReducer.java:253) 
  3.     at org.apache.hadoop.mapred.ReduceTask.runOldReducer(ReduceTask.java:444) 
  4.     at org.apache.hadoop.mapred.ReduceTask.run(ReduceTask.java:392) 
  5.     at org.apache.hadoop.mapred.YarnChild$2.run(YarnChild.java:164) 
  6.     at java.security.AccessController.doPrivileged(Native Method) 
  7.     at javax.security.auth.Subject.doAs(Subject.java:422) 
  8.     at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1924) 
  9.     at org.apache.hadoop.mapred.YarnChild.main(YarnChild.java:158) 
  10. Caused by: org.apache.hadoop.hive.ql.metadata.HiveException: java.lang.IllegalArgumentException: KeyValue size too large 
  11.     at org.apache.hadoop.hive.ql.exec.GroupByOperator.processOp(GroupByOperator.java:763) 
  12.     at org.apache.hadoop.hive.ql.exec.mr.ExecReducer.reduce(ExecReducer.java:244) 
  13.     ... 7 more 
  14. Caused by: java.lang.IllegalArgumentException: KeyValue size too large 
  15.     at org.apache.hadoop.hbase.client.HTable.validatePut(HTable.java:1577) 
  16.     at org.apache.hadoop.hbase.client.BufferedMutatorImpl.validatePut(BufferedMutatorImpl.java:158) 
  17.     at org.apache.hadoop.hbase.client.BufferedMutatorImpl.mutate(BufferedMutatorImpl.java:133) 
  18.     at org.apache.hadoop.hbase.client.BufferedMutatorImpl.mutate(BufferedMutatorImpl.java:119) 
  19.     at org.apache.hadoop.hbase.client.HTable.put(HTable.java:1085) 
  20.     at org.apache.hadoop.hive.hbase.HiveHBaseTableOutputFormat$MyRecordWriter.write(HiveHBaseTableOutputFormat.java:146) 
  21.     at org.apache.hadoop.hive.hbase.HiveHBaseTableOutputFormat$MyRecordWriter.write(HiveHBaseTableOutputFormat.java:117) 
  22.     at org.apache.hadoop.hive.ql.io.HivePassThroughRecordWriter.write(HivePassThroughRecordWriter.java:40) 
  23.     at org.apache.hadoop.hive.ql.exec.FileSinkOperator.processOp(FileSinkOperator.java:717) 
  24.     at org.apache.hadoop.hive.ql.exec.Operator.forward(Operator.java:815) 
  25.     at org.apache.hadoop.hive.ql.exec.SelectOperator.processOp(SelectOperator.java:84) 
  26.     at org.apache.hadoop.hive.ql.exec.Operator.forward(Operator.java:815) 
  27.     at org.apache.hadoop.hive.ql.exec.GroupByOperator.forward(GroupByOperator.java:1007) 
  28.     at org.apache.hadoop.hive.ql.exec.GroupByOperator.processAggr(GroupByOperator.java:818) 
  29.     at org.apache.hadoop.hive.ql.exec.GroupByOperator.processKey(GroupByOperator.java:692) 
  30.     at org.apache.hadoop.hive.ql.exec.GroupByOperator.processOp(GroupByOperator.java:758) 
  31.     ... 8 more 

03 該線上 Hbase 問題的問題原因

其實(shí)以上作業(yè)的報(bào)錯(cuò)日志還是比較詳細(xì)的:Caused by: java.lang.IllegalArgumentException: KeyValue size too large at org.apache.hadoop.hbase.client.HTable.validatePut(HTable.java:1577);

  • 即報(bào)錯(cuò)詳細(xì)信息是:KeyValue size too large;
  • 報(bào)錯(cuò)來自 Hbase (而不是 HIVE)的類,從類名看是 hbase 客戶端在對(duì)待插入數(shù)據(jù)校驗(yàn)時(shí)發(fā)現(xiàn)了錯(cuò)誤:org.apache.hadoop.hbase.client.HTable.validatePut(HTable.java:1577);

熟悉 Hbase 的小伙伴(其實(shí)不熟悉 Hbase 的小伙伴,也能從報(bào)錯(cuò)信息和報(bào)錯(cuò)類上猜到一點(diǎn)點(diǎn)),從以上信息能夠猜到,是 Hbase 對(duì)每條記錄的 KyeValue 的大小做了限制,當(dāng)實(shí)際插入的 KeyValue 的大小超過該大小限制閾值時(shí),就會(huì)報(bào)上述錯(cuò)誤。

什么是 KeyValue 呢?

  • 這涉及到 Hbase 的存儲(chǔ)結(jié)構(gòu),Hbase 內(nèi)部是通過 KeyValue 結(jié)構(gòu)來存儲(chǔ)表數(shù)據(jù)的;
  • 大致上大家可以認(rèn)為:某個(gè) KeyValue 對(duì)應(yīng)的是 Hbase 大寬表中的某行的某列;
  • 每個(gè) KeyVlue 內(nèi)部內(nèi)容包含:rowKey+CF(ColumnFamily)+CQ(Column qualifier)+Timestamp+Value;
  • 詳細(xì)說明見官方文檔,截圖如下:

Hbase 為什么要限制每個(gè) KeyValue 的大小呢?

  • 究其原因,是因?yàn)?Hbase 需要在 hdfs 存儲(chǔ)引擎(基于分磁盤)之上提供對(duì)數(shù)據(jù)實(shí)時(shí)讀寫的支持;
  • Hbase 在內(nèi)部數(shù)據(jù)讀寫時(shí)使用了 LSM 數(shù)據(jù)結(jié)構(gòu) (Log-Structured-Merge Tree),這背后涉及到了大量對(duì)內(nèi)存的使用(讀數(shù)據(jù)時(shí)使用 BlockCache,寫數(shù)據(jù)時(shí)使用 memStore),也涉及到了內(nèi)存數(shù)據(jù)的異步 flush 和 hfile 文件的異步 compaction;(當(dāng)然為了容錯(cuò),又涉及到了 wal Hlog);
  • 因?yàn)樯婕暗交趦?nèi)存提供對(duì)數(shù)據(jù)讀寫的支持,所以需要限制使用的內(nèi)存的總大小,由于內(nèi)存 BlockCache 中緩存的數(shù)據(jù)是以Block 為單位的,而Block內(nèi)部存儲(chǔ)的是一個(gè)個(gè) KeyValue, 所以從細(xì)節(jié)來講也需要限制每個(gè) KeyValue的大小;
  • 這里的 Block 是 Hbase的概念,不是 HDFS Block; (Hbase 每個(gè) Block 的默認(rèn)大小是 64KB, HDFS 每個(gè)BLOCK的默認(rèn)大小一般是 128MB);

04 該線上 Hbase 問題的擴(kuò)展知識(shí)-不同 Hbase 版本相關(guān)的參數(shù)

Hbase 作為一個(gè)流行的 Nosql數(shù)據(jù)庫,推出十多年來,目前有多個(gè)經(jīng)典版本:

  • 0.98;-- 該版本比較老了,部分遺留線上應(yīng)用還有使用該版本的;
  • 1.2.x;(1.4.x) -- 1.2.x 和 1.4.x 都是1.x 系列下用的比較多的穩(wěn)定版本
  • 2.1.x(2.4.x) -- 2.1.x 和 2.4.x 都是2.x系列下用的比較多的穩(wěn)定版本
  • 3.0.0-alpha-1 -- 3.x 系列目前還不是穩(wěn)定版

對(duì)應(yīng)該 “KeyValue size too large” 問題,不同版本推出了不同的相關(guān)參數(shù):

  • 在hbase-1.4 以前的版本中,(包括hbase 1.2.0-cdh5.14.2 和 hbase 1.2.0-cdh5.16.2),只有一個(gè)客戶端參數(shù) hbase.client.keyvalue.maxsize;
  • 在 hbase-1.4 及以后版本中,除了該客戶端參數(shù) hbase.client.keyvalue.maxsize,還有一個(gè)服務(wù)端參數(shù) hbase.server.keyvalue.maxsize;

其實(shí),由于筆者并沒有持續(xù)跟進(jìn) HBASE 社區(qū)對(duì) feautre 和 issue相關(guān)的討論(大部分使用者可能都不會(huì)),所以也是在查閱不同版本的官方文檔時(shí)留意到了上述細(xì)節(jié),然后通過在本地 IDEA 中使用 git->show history 對(duì)比不同版本 HBASE 中 hbase-default.xml 的源碼,進(jìn)而確認(rèn)到了JIRA記錄號(hào),并在JIRA中確認(rèn)了這點(diǎn):

正如該 JIRA 中描述:

HBASE-18043:

For sake of service protection we should not give absolute trust to clients regarding resource limits that can impact stability, like cell size limits. We should add a server side configuration that sets a hard limit for individual cell size that cannot be overridden by the client. We can keep the client side check, because it's expensive to reject a RPC that has already come in.

所以,不同版本中遇到不同情況,可能會(huì)包的錯(cuò)誤主要有兩個(gè):

  • 情況1:Hbase KeyValue size too large
  • 情況2:Cell with size 25000046 exceeds limit of 10485760 bytes

報(bào)錯(cuò)情況一和報(bào)錯(cuò)情況而,問題原因如下:

報(bào)錯(cuò)情況一:沒有配置客戶端參數(shù) hbase.client.keyvalue.maxsize,且實(shí)際插入的 keyvalue 的大小超過了該客戶端參數(shù)的默認(rèn)大小限制;

報(bào)錯(cuò)情況二:程序設(shè)置調(diào)大了客戶端參數(shù) hbase.client.keyvalue.maxsize,但沒有調(diào)大服務(wù)端參數(shù) hbase.server.keyvalue.maxsize,且實(shí)際插入的 keyvalue 小于該客戶端參數(shù),但大于該服務(wù)端參數(shù):

報(bào)錯(cuò)情況二,某次作業(yè)日志:

  1. Exception in thread "main"org.apache.hadoop.hbase.DoNotRetryIOException: 
  2.  org.apache.hadoop.hbase.DoNotRetryIOException: Cell with size 25000046 exceeds limit of 10485760 bytes  at org.apache.hadoop.hbase.regionserver.RSRpcServices.checkCellSizeLimit(RSRpcServices.java:944) 
  3.     at org.apache.hadoop.hbase.regionserver.RSRpcServices.mutate(RSRpcServices.java:2792) 
  4.     at org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos$ClientService$2.callBlockingMethod(ClientProtos.java:42000) 
  5.     at org.apache.hadoop.hbase.ipc.RpcServer.call(RpcServer.java:413) 
  6.     at org.apache.hadoop.hbase.ipc.CallRunner.run(CallRunner.java:130) 
  7.     at org.apache.hadoop.hbase.ipc.RpcExecutor$Handler.run(RpcExecutor.java:324) 
  8.     at org.apache.hadoop.hbase.ipc.RpcExecutor$Handler.run(RpcExecutor.java:304) 

報(bào)錯(cuò)情況二,某次報(bào)錯(cuò)截圖:

05 該線上 Hbase 問題的解決方案

知道了問題原因,其實(shí)解決方法也就呼之欲出了,在確認(rèn)要插入的業(yè)務(wù)數(shù)據(jù)沒有異常,確實(shí)需要調(diào)大 keyvalue 限制的閾值時(shí),大體總結(jié)下,有以下解決辦法:

  • 方法一:修改配置文件 hbase-site.xml, 調(diào)大客戶端參數(shù) hbase.client.keyvalue.maxsize 的值;
  • 方法二:如果使用了 HBASE JAVA API, 可以修改代碼使用 configuration 對(duì)象修改此客戶端參數(shù)的默認(rèn)配置:Configuration conf = HBaseConfiguration.create();
  • conf.set("hbase.client.keyvalue.maxsize","20971520");
  • 方法三:如果使用了 HIVE,可以在客戶端覆蓋該客戶端參數(shù):set hbase.client.keyvalue.maxsize=0; (hive sql中)
  • 說明:一般該客戶端參數(shù)和服務(wù)端參數(shù),默認(rèn)值應(yīng)該配置一樣;當(dāng)更改服務(wù)端參數(shù)時(shí),需要重啟服務(wù)端才能生效;當(dāng)更改客戶端參數(shù)時(shí),不同客戶端設(shè)置的值可以不同,且不需要重啟服務(wù)端;
  • 在CDH中配置更改截圖如下:

06 該線上 Hbase 問題的技術(shù)背景

  • Hbase 內(nèi)部是通過 KeyValue 結(jié)構(gòu)來存儲(chǔ)表數(shù)據(jù)的,某個(gè) KeyValue 對(duì)應(yīng)的是 Hbase 大寬表中的某行的某列,每個(gè) KeyVlue 內(nèi)部內(nèi)容包含:rowKey+CF(ColumnFamily)+CQ(Column qualifier)+Timestamp+Value;
  • hbase 在進(jìn)行 PUT 操作的時(shí)候,會(huì)逐個(gè)檢查要插入的每個(gè)列 (keyvalue cell) 的大小,當(dāng)其大小大于 maxKeyValueSize 時(shí),就會(huì)拋出異常,拒絕寫入;
  • maxKeyValueSize 大小相關(guān)的參數(shù),在hbase-1.4 以前的版本中,(包括hbase 1.2.0-cdh5.14.2 和 hbase 1.2.0-cdh5.16.2),只有一個(gè)客戶端參數(shù) hbase.client.keyvalue.maxsize;
  • maxKeyValueSize 大小相關(guān)的參數(shù),在 hbase-1.4 及以后版本中,除了該客戶端參數(shù) hbase.client.keyvalue.maxsize,還有一個(gè)服務(wù)端參數(shù) hbase.server.keyvalue.maxsize;
  • Hbase 限制每個(gè) KeyValue 大小的原因,主要在于:
    • Hbase 需要在 hdfs 存儲(chǔ)引擎(基于分磁盤)之上提供對(duì)數(shù)據(jù)實(shí)時(shí)讀寫的支持,因此 Hbase 在內(nèi)部數(shù)據(jù)讀寫時(shí)使用了 LSM 數(shù)據(jù)結(jié)構(gòu) (Log-Structured-Merge Tree),這背后涉及到了大量對(duì)內(nèi)存的使用(讀數(shù)據(jù)時(shí)使用 BlockCache,寫數(shù)據(jù)時(shí)使用 memStore),也涉及到了內(nèi)存數(shù)據(jù)的異步 flush 和 hfile 文件的異步 compaction;(當(dāng)然為了容錯(cuò),又涉及到了 wal Hlog);
    • 因?yàn)樯婕暗交趦?nèi)存提供對(duì)數(shù)據(jù)讀寫的支持,所以需要限制使用的內(nèi)存的總大小,由于內(nèi)存 BlockCache 中緩存的數(shù)據(jù)是以Block 為單位的,而Block內(nèi)部存儲(chǔ)的是一個(gè)個(gè) KeyValue, 所以從細(xì)節(jié)來講也需要限制每個(gè) KeyValue的大小;
    • 這里的 Block 是 Hbase的概念,不是 HDFS Block; (Hbase 每個(gè) Block 的默認(rèn)大小是 64KB, HDFS 每個(gè)BLOCK的默認(rèn)大小一般是 128MB);
  • 該客戶端參數(shù) hbase.client.keyvalue.maxsize,和服務(wù)端參數(shù)hbase.server.keyvalue.maxsize,集群級(jí)別的默認(rèn)配置推薦保持一致,且不推薦在集群級(jí)別配置這兩個(gè)參數(shù)為0或更小(即禁用大小檢查),因?yàn)榇藭r(shí)可能會(huì)造成某個(gè)cell 存很大的數(shù)據(jù)比如 1G,此時(shí)集群性能就會(huì)大打折扣;
  • 服務(wù)端參數(shù)只能在服務(wù)端進(jìn)行配置,且配置后要重啟服務(wù)端的 hbase, 其做用是 “This is a safety setting to protect the server from OOM situations.”;
  • 客戶端參數(shù)可以在服務(wù)端進(jìn)行全局默認(rèn)配置,也可以在客戶端進(jìn)行定制配置,不同客戶端設(shè)置的值可以不同,但不能大于服務(wù)端的值,且客戶端配置后不需要重啟服務(wù)端,其含義是:一個(gè)KeyValue實(shí)例的最大size(一個(gè)KeyValue在io時(shí)是不能進(jìn)一步分割的);
  • 客戶端參數(shù),具體需要設(shè)置為多大,需要根據(jù)業(yè)務(wù)允許的最大keyValue是多少來進(jìn)行配置,默認(rèn)是10M,一般是以默認(rèn)值10M為基礎(chǔ),如果有客戶遇到以上報(bào)錯(cuò),且實(shí)際的KEYVALUE也不是業(yè)務(wù)臟數(shù)據(jù),就調(diào)大1倍到20MB看看;
  • 在通過hive外表使用 HBaseStorageHandler 向 HBASE 寫數(shù)據(jù)時(shí),可以直接在beeline中更改配置客戶端參數(shù) (set hbase.client.keyvalue.maxsize=10485760),不需要重啟hbase服務(wù)端;
  • 在探究某個(gè)開源組件的某個(gè)類或配置文件,在不同版本的變化歷史時(shí),可以通過 git clone 在本地克隆創(chuàng)建 git repository,然后在本地 IDEA 中通過使用命令 git->show history 對(duì)比不同版本中類或配置文件的,進(jìn)而確認(rèn)到 JIRA 記錄號(hào),并在JIRA中確認(rèn)相關(guān)細(xì)節(jié);
  • 更多關(guān)于hbase數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)的細(xì)節(jié):

 

  • hbase 中的數(shù)據(jù),可以有多個(gè)columnFamily, 每個(gè) columnFamily 內(nèi)部可以有多個(gè)column;
    • 每個(gè) ColumnsFamily 落地到hdfs上的文件是 hfile/storeFile, storeFile 是由 data block組成的(block 是IO和壓縮的基本單位,默認(rèn)64KB);(Within an HFile, HBase cells are stored in data blocks as a sequence of KeyValues;KeyValue instances are aggregated into blocks, which are indexed and Indexes also have to be stored; Blocksize is configurable on a per-ColumnFamily basis);
    • 每個(gè) block 內(nèi)部存儲(chǔ)了多個(gè)columns,每個(gè)column都是以 keyvalue 的形式存儲(chǔ)的,每個(gè)keyvalue的大小受hbase.clent.keyvalue.maxsize/hbase.server.keyvalue.maxsize限制的;
    • compression and DATA BLOCK ENCODING doesn't help with the cell size check, as compress and data block encoding happens when flush memstore to hfile and compaction of hfile;
    • HBase supports several different compression algorithms which can be enabled on a ColumnFamily. Data block encoding attempts to limit duplication of information in keys, taking advantage of some of the fundamental designs and patterns of HBase, such as sorted row keys and the schema of a given table. Compressors reduce the size of large, opaque byte arrays in cells, and can significantly reduce the storage space needed to store uncompressed data.

 

責(zé)任編輯:武曉燕 來源: 明哥的IT隨筆
相關(guān)推薦

2019-09-10 10:31:10

JVM排查解決

2020-11-16 07:19:17

線上函數(shù)性能

2021-11-23 21:21:07

線上排查服務(wù)

2024-10-10 15:32:51

2024-03-18 09:10:00

死鎖日志binlog

2018-01-15 14:50:49

APP轉(zhuǎn)讓App賬號(hào)

2023-03-29 09:36:32

2021-04-13 18:17:48

Hbase集群配置

2023-01-04 18:32:31

線上服務(wù)代碼

2019-04-15 13:15:12

數(shù)據(jù)庫MySQL死鎖

2011-04-07 11:20:21

SQLServer

2020-05-04 11:04:46

HTTP劫持寬帶

2024-10-15 09:27:36

2020-11-16 12:35:25

線程池Java代碼

2022-06-06 11:31:31

MySQL數(shù)據(jù)查詢

2022-07-11 13:58:14

數(shù)據(jù)庫業(yè)務(wù)流程系統(tǒng)

2023-01-16 14:49:00

MongoDB數(shù)據(jù)庫

2020-09-16 08:26:18

圖像定位尺寸

2010-09-07 11:16:14

SQL語句

2022-01-10 10:26:30

Kubernetes抓包環(huán)境
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)