億級資料多條件組合查詢——秒級響應解決方案
1 概述
組合查詢為多條件組合查詢,在很多場景下都有使用。購物網站中通過勾選類別、價格、銷售量範圍等屬性來對所有的商品進行篩選,篩選出滿足客戶需要的商品,這是一種典型的組合查詢。在小資料量的情況下,後臺通過簡單的sql語句便能夠快速過濾出需要的資料,但隨著資料量的增加,繼續使用sql語句,查詢效率會直線下降。當資料量達到一定的量級,伺服器將會不堪重負甚至面臨掛掉的危險,並且大資料量的儲存也成為了一個問題。本文將討論在億級資料的情況下,多條件組合查詢秒級響應的解決方案。
2 方案思考
2.1 資料儲存
假定每條資料有10個欄位,每個欄位的大小為4Byte,共有1億條資料。通過傳統的關係型資料庫mysql,使用JDBC批處理和事務混合的方式對資料進行插入,插入一億資料大約需要半小時,欄位可能會出現為空的情況,導致冗餘。針對海量資料的儲存,現如今使用較多的是HBase。使用HBase的好處有三:其一,它是非關係型資料庫,欄位為空的值只在邏輯上存在,在空間上不存在,因此解決了冗餘的問題;其二,它是面向列的資料庫,能夠通過簡單的API呼叫對欄位進行橫向擴充套件;其三,它是分部署資料庫,表的RowKey 按照字典排序,Region按照RowKey設定split point進行shard,通過這種方式實現全域性、分散式索引,通過RowKey索引資料能夠在毫秒級返回。Hbase插入資料可以呼叫批量插入或者通過MR程式插入,實測在批量提交資料條數設定為1000,開10個執行緒的情況下,插入一億資料大約需要10分鐘。若需要加速插入速度,可以通過增加批量提交數、調整執行緒數或者使用MR程式進行Hbase的寫入。Hbase本身是分散式資料庫,資料儲存可以儲存在多個節點上,使用Zookeeper統一管理,提供資料備份和故障恢復的功能。因此使用Hbase作為資料倉庫,對結構化資料進行儲存。
2.2 資料查詢
Hbase中的資料查詢只有兩種方式:一是使用get 'tablename', 'rowkey‘’
直接通過rowkey進行查詢,億級資料的查詢結果可以在毫秒內返回;二是設定過濾器對全表進行Scan
掃描,該查詢方式在海量資料的情況下耗時十分長,當然也和伺服器的效能有關。我們的需求是秒級響應,如果使用全表掃描方式,資料量達到萬級或者十萬級就無法實現實時響應了,要進行這樣的查詢,往往是要通過類似Hive、Pig等系統進行全表的MapReduce計算,這種方式既浪費了機器的計算資源,又因高延遲使得應用黯然失色。因此我們考慮使用rowKey對資料進行查詢,如果我們使用rowKey對全表進行多條件組合查詢,這將對rowKey的設定要求十分高,面向業務而言這對程式設計師十分不友好,因此我們需要通過建立二級索引的方式,按索引的種類掃描各自獨立的單索引表,最後將掃描結果merge,得到目標rowKey。HBase有原生的建立二級索引的方式,即使用HBase的coprocessor協處理器,可以根據業務進行靈活的設定,但較為複雜,本文討論使用一種業務模式較為固定,但更加簡單直接的方式建立索引——Solr。Solr是一個獨立的企業級搜尋應用伺服器,是Apache Lucene專案的開源企業搜尋平臺。其主要功能包括全文檢索、命中標示、分面搜尋、動態聚類、資料庫整合,以及富文字(如Word、PDF)的處理。Solr是高度可擴充套件的,並提供了分散式搜尋和索引複製。我們可以直接使用Solr這一元件,通過修改配置檔案以實現相關的業務需求。通過批量建立索引的方式對HBase中的一億條資料的10個欄位構建索引,耗時為3383s
public class ThreadsCreateIndexWork {
private static Logger logger = LoggerFactory.getLogger(ThreadsCreateIndexWork.class);
public static void main(String[] args) throws IOException, SolrServerException {
if(args.length < 3) {
logger.info("[tableName | queueSize | threadCount]" );
logger.info("e.g.| test1 20000 20");
}
String tableName = args[0];
String queueSize = args[1];
String threadCount = args[2];
long start = System.currentTimeMillis();
final Configuration conf;
Properties prop = PropertiesReaderUtils.getProperties("conf/path.properties");
String server = prop.getProperty("solr.server");
SolrServer solrServer = new ConcurrentUpdateSolrServer(server, Integer.parseInt(queueSize), Integer.parseInt(threadCount));
conf = HBaseConfiguration.create();
HTable table = new HTable(conf, tableName); // 這裡指定HBase表名稱
Scan scan = new Scan();
scan.addFamily(Bytes.toBytes("people")); // 這裡指定HBase表的列族
scan.setCaching(500);
scan.setCacheBlocks(false);
ResultScanner ss = table.getScanner(scan);
try {
for (Result r : ss) {
SolrInputDocument solrDoc = new SolrInputDocument();
solrDoc.addField("rowkey", new String(r.getRow()));
for (KeyValue kv : r.raw()) {
String fieldName = new String(kv.getQualifier());
String fieldValue = new String(kv.getValue());
if (fieldName.equalsIgnoreCase("upperClothing")
|| fieldName.equalsIgnoreCase("lowerClothing")
|| fieldName.equalsIgnoreCase("coatStyle")
|| fieldName.equalsIgnoreCase("trousersStyle")
|| fieldName.equalsIgnoreCase("sex")
|| fieldName.equalsIgnoreCase("age")
|| fieldName.equalsIgnoreCase("angle")
|| fieldName.equalsIgnoreCase("bag")
|| fieldName.equalsIgnoreCase("umbrella")
|| fieldName.equalsIgnoreCase("featureType")){
solrDoc.addField(fieldName, fieldValue);
}
}
solrServer.add(solrDoc);
}
ss.close();
table.close();
} catch (IOException e) {
} finally {
ss.close();
table.close();
}
long time = System.currentTimeMillis() - start;
logger.info("---------- create index with thread use time " + String.valueOf(time));
}
}
ConcurrentUpdateSolrServer
類可以使用多執行緒向SolrCloud的多個節點發送http請求,queueSize
為佇列大小,即往Solr中一次性批量add的資料數目,threadCount
為開啟的執行緒數,可以根據伺服器效能的不同進行自定義,以提高構建索引的速度。筆者對1000w條資料進行引數調整測試,得到如下結果:
queueSize | threadNum | Time (s) |
---|---|---|
10000 | 20 | 274 |
20000 | 20 | 250 |
20000 | 30 | 255 |
20000 | 40 | 254 |
30000 | 20 | 255 |
因此測試中選用的引數為queueSize:20000
和threadNum:20
,索引構建速度為4w/s
,還嘗試通過修改scan.setCaching(500);
的大小來提高構建速度,但是發現該快取大小對構建速度的影響可以忽略不計,應該是索引構建速度低於HBase的Scan速度,因此暫時沒有必要對HBase的Scan操作進行加速。Solr對構建索引的服務進行了上層封裝,提供一個web服務的介面,可以直接通過視覺化介面對結果進行查詢。
3 解決方案
綜上,針對億級資料多條件組合查詢,給出的解決方案是使用HBase+Solr
的方式,CDH將HBase和Solr都以元件的方式提供出來,可以使用CDH平臺對HBase和Solr進行統一的管理。Hbase用於儲存海量資料,Solr使用SolrCloud模式進行部署,提供索引構建和查詢。索引的建立可以通過介面離線批量建立,也可以使用HBase Indexer連線HBase和Solr,提供自動化索引構建,CDH平臺也集成了Hbase Indexer(Lily HBase Indexer)這一元件。
4 方案測試
筆者將一億條包含10個欄位的資料開啟10個執行緒插入Hbase中,然後使用Solr對10個欄位構建了索引,在Solr的視覺化介面進行查詢,查詢結果如下圖所示。
其中,QTime
為響應時間,q
為查詢語句,wt
為請求格式(設定請求格式為xml響應速度更快),numFound
為找到符合查詢條件的資料條數,docs
為返回的資料也就是rowKey。可以看到,組合查詢都能夠在秒級響應返回響應rowKey,而通過rowKey在HBase中返回該條資料的所有欄位可以在毫秒級響應,如下圖所示:
至此,可以證明,億級資料多條件組合查詢使用HBase+Solr
的解決方案能夠滿足秒級響應的需求。