SparkSQL數據DataFrame向ElasticSearch寫入的優化,親測提高數倍

  1. 前言
    最近sparksql寫入elasticsearch數據量逐漸增大,所以需要優化寫入的速度.
    先說一下集羣情況.
    es集羣:elasticsearch-6.2.4, 機器配置:5臺4C*16G阿里雲機器.
    spark: 2.1.3.

  2. 優化方向
    從spark參數和es索引兩個方向進行優化

  3. spark參數
    es提供了一套完整的hadoop生態支持.可以完整的支持spark讀寫es.
    在spark的config可以設置兩個參數,es.batch.size.bytes 以及es.batch.size.entries,這兩個參數表示寫入時es bulk操作的batch大小和條數.這些設置對應到每個task中.hadoop/spark 相關配置信息見鏈接:es spark支持config
    這兩個參數默認1mb和1000條,在調節的時候也不是越大越好,需要根據自己的數據不斷的去測試.

  4. index參數

    1. mapping設置
      精細設置每個字段的type類型,不需要分詞的字段儘量設置爲keyword.所有的字段都精細設置.分詞不僅會佔用額外空間,還很影響寫入速度.
      如果沒有場景用到_all字段,那麼禁用_all字段.
    2. setting設置
      1. number_of_replicas:在創建索引的時候(或者數據寫入的時候),設置副本數爲0,number_of_replicas:0,在大量數據寫入的時候,數據從主分片往副本同步數據,也是很消耗資源的.在數據寫入完成後,可以恢復副本,副本的主要作用是容災和負載均衡,可以參考elasticsearch權威指南:elasticsearch權威指南
      2. refresh_interval:在實時性要求沒那麼高的時候,可以調大索引refresh_interval參數.因爲我的是離線項目,所以我這裏設置爲-1. 默認情況下寫入到es的數據並不是馬上就刷到磁盤,先放在 in-memory buffer,但客戶端是讀取不到in-memory buffer中的數據,爲了實時查詢,需要定期(默認1s)將該數據刷寫到介於es和磁盤之間的filesystem cache 即refresh,該操作輕量級的 。寫入到filesystem cache相當於創建新的segment 是可以被客戶端讀取到的, 默認屬性(閾值是1s)由於快速的刷數據導致很多小量的filesystem cache,同時寫入到filesystem cache仍然有一些性能消耗,所以根據應用的使用場景,如果是關注寫入速度並不關注實時查詢,可以適當調整默認的閾值的,該屬性是在創建索引(屬性值爲:index.refresh_interval)的時候設置的.
      3. translog.durability: 設置translog.durability爲async.translog.durability 默認值是request,該屬性類似於hbase 中的WAL,是爲了防止數據寫入後 ,還沒有落盤之前 出現宕機導致數據丟失。client提交request後,除了在in-memory buffer 添加新的文檔/操作,還需要在translog 追加新的文檔/操作 ,以保證數據的可靠性 。 其實translog.durability 屬性可以設置爲async,當然async並不能保證新的文檔/操作一定寫入到trans-log,如果寫到translog 沒有成功 剛好這時也出現宕機,重啓後從translog恢復時就會有數據丟失,所以我們需要在做好數據可靠性和寫入效率之間做好權衡後再設置 。translog在 滿足下面其中一個條件時 會執行commit 請求即filesystem cache 刷寫到磁盤 condition1:緩存數據達到512M(default) condition2 : 緩存時間達到5s(default),commit成功後translog會刪除. 這個參數也是在創建索引的時候設置的.
        4.translog.sync_interval, translog.flush_threshold_size 設置translog.sync_interval, translog.flush_threshold_size,這兩個參數的作用已經在上面說明了.可以再創建索引的時候把這兩個參數設大一些.
  5. 修改elasticsearch的yml文件
    網上很多博客都說修改yml的部分參數,也可以優化寫入速度,但是我沒有測.還是寫出來供大家參考.

    1. indices.memory.index_buffer_size,indices.memory.min_index_buffer_size,indexing buffer在爲 doc 建立索引時使用,當緩衝滿時會刷入磁盤,生成一個新的 segment, 這是除refresh_interval外另外一個刷新索引,生成新 segment 的機會. 每個 shard 有自己的 indexing buffer,下面的關於這個 buffer 大小的配置需要除以這個節點上所有的 shard 數量
    2. 設置index、merge、bulk、search的線程數和隊列數
      # Search pool
      thread_pool.search.size: 5
      thread_pool.search.queue_size: 100
      # 這個參數慎用!強制修改cpu核數,以突破寫線程數限制
      # processors: 16
      # Bulk pool
      thread_pool.bulk.size: 16
      thread_pool.bulk.queue_size: 300
      # Index pool
      thread_pool.index.size: 16
      thread_pool.index.queue_size: 300
      
      1. 設置節點之間的故障檢測配置,
        大數量寫入的場景,會佔用大量的網絡帶寬,很可能使節點之間的心跳超時。並且默認的心跳間隔也相對過於頻繁(1s檢測一次)
      discovery.zen.fd.ping_timeout: 120s
      discovery.zen.fd.ping_retries: 6
      discovery.zen.fd.ping_interval: 30s
      
  6. 其他調整

    1. 使用自動生成doc id, 網上很多博客都說使用自動生成文檔id能比指定文檔id塊很多, 可能是我水平有限.我測下來使用自動生成穩定id是比指定文檔id快一些,但是沒有快到那麼多.
    2. 磁盤,SSD磁盤比機械磁盤速度能快上不少,親測,推薦使用SSD磁盤.
    3. 合理的分片數,建索引的時候設置合適的分片數,也可以提高數據寫入的速度.這個參數需要根據自己的集羣規模以及機器配置去測.
    4. 合適的mapping字段數.這個親測,同樣數據量的兩個Dataframe,一個字段數在60左右,一個在280左右,建立對應字段數的索引,寫入速度大概差3~4倍左右.
  7. 最後, 我這裏只搭配調整了3,4,6裏的大部分設置,寫入速度大概提升了4~5倍左右. 這裏只是記錄了實際對寫入有提升的一些配置,還沒有深入研究有擴展繼續填坑.

    參考:elasticsearch寫入優化記錄,從3000到8000/s
    spark 向elasticsearch 優化寫入數據

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章