介紹
如果你使用elasticsearch來存儲你的日志,本文給你提供一些做法和建議。
如果你想從多台主機向elasticsearch匯集日志,你有以下多種選擇:
- Graylog2 安裝在一台中心機上,然后它負責往elasticsearch插入日志,而且你可以使用它那個漂亮的搜索界面~
- Logstash 他有很多特性,包括你能輸入什么日志,如何變換過濾,最好輸出到哪里。其中就有輸出到elasticsearch,包括直接輸出和通過RabbitMQ的river方式兩種。
- Apache Flume 這個也可以從海量數據源中獲取日志,用”decorators”修改日志,也有各種各樣的”sinks”來存儲你的輸出。和我們相關的是elasticflume sink。
- omelasticsearch Rsyslog的輸出模塊。你可以在你的應用服務器上通過rsyslog直接輸出到elasticsearch,也可以用rsyslog傳輸到中心服務器上來插入日志。或者,兩者結合都行。具體如何設置參見rsyslog Wiki。
- 定制方案。比如,專門寫一個腳本從天南海北的某個服務器傳輸你的日志到elasticsearch。
根據你設定的不同,最佳配置也變化不定。不過總有那么幾個有用的指南可以推薦一下:
內存和打開的文件數
如果你的elasticsearch運行在專用服務器上,經驗值是分配一半內存給elasticsearch。另一半用於系統緩存,這東西也很重要的。
你可以通過修改ES_HEAP_SIZE環境變量來改變這個設定。在啟動elasticsearch之前把這個變量改到你的預期值。另一個選擇上球該elasticsearch的ES_JAVA_OPTS變量,這個變量時在啟動腳本(elasticsearch.in.sh或elasticsearch.bat)里傳遞的。你必須找到-Xms和-Xmx參數,他們是分配給進程的最小和最大內存。建議設置成相同大小。嗯,ES_HEAP_SIZE其實就是干的這個作用。
你必須確認文件描述符限制對你的elasticsearch足夠大,建議值是32000到64000之間。關於這個限制的設置,另有教程可以參見。
目錄數
一個可選的做法是把所有日志存在一個索引里,然后用ttl field來確保就日志被刪除掉了。不過當你日志量夠大的時候,這可能就是一個問題了,因為用TTL會增加開銷,優化這個巨大且唯一的索引需要太長的時間,而且這些操作都是資源密集型的。
建議的辦法是基於時間做目錄。比如,目錄名可以是YYYY-MM-DD的時間格式。時間間隔完全取決於你打算保留多久日志。如果你要保留一周,那一天一個目錄就很不錯。如果你要保留一年,那一個月一個目錄可能更好點。目錄不要太多,因為全文搜索的時候開銷相應的也會變大。
如果你選擇了根據時間存儲你的目錄,你也可以縮小你的搜索范圍到相關的目錄上。比如,如果你的大多數搜索都是關於最近的日志的,那么你可以在自己的界面上提供一個”快速搜索”的選項只檢索最近的目錄。
輪轉和優化
移除舊日志在有基於時間的目錄后變得異常簡單:
$ curl -XDELETE 'http://localhost:9200/old-index-name/'
這個操作的速度非常快,和刪除大小差不多的少量文件速度接近。你可以放進crontab里半夜來做。
Optimizing indices是在非高峰時間可以做的一件很不錯的事情。因為它可以提高你的搜索速度。尤其是在你是基於時間做目錄的情況下,更建議去做了。因為除了當前的目錄外,其他都不會再改,你只需要對這些舊目錄優化一次就一勞永逸了。
$ curl -XPOST 'http://localhost:9200/old-index-name/_optimize'
分片和復制
通過elasticsearch.yml或者使用REST API,你可以給每個目錄配置自己的設定。具體細節參見鏈接。
有趣的是分片和復制的數量。默認情況下,每個目錄都被分割成5個分片。如果集群中有一個以上節點存在,每個分片會有一個復制。也就是說每個目錄有一共10個分片。當往集群里添加新節點的時候,分片會自動均衡。所以如果你有一個默認目錄和11台服務器在集群里的時候,其中一台會不存儲任何數據。
每個分片都是一個Lucene索引,所以分片越小,elasticsearch能放進分片新數據越少。如果你把目錄分割成更多的分片,插入速度更快。請注意如果你用的是基於時間的目錄,你只在當前目錄里插入日志,其他舊目錄是不會被改變的。
太多的分片帶來一定的困難——在空間使用率和搜索時間方面。所以你要找到一個平衡點,你的插入量、搜索頻率和使用的硬件條件。
另一方面,復制幫助你的集群在部分節點宕機的時候依然可以運行。復制越多,必須在線運行的節點數就可以越小。復制在搜索的時候也有用——更多的復制帶來更快的搜索,同時卻增加創建索引的時間。因為對豬分片的修改,需要傳遞到更多的復制。
映射_source和_all
Mappings定義了你的文檔如何被索引和存儲。你可以,比如說,定義每個字段的類型——比如你的syslog里,消息肯定是字符串,嚴重性可以是整數。怎么定義映射參見鏈接。
映射有着合理的默認值,字段的類型會在新目錄的第一條文檔插入的時候被自動的檢測出來。不過你或許會想自己來調控這點。比如,可能新目錄的第一條記錄的message字段里只有一個數字,於是被檢測為長整型。當接下來99%的日志里肯定都是字符串型的,這樣Elasticsearch就沒法索引他們,只會記錄一個錯誤日志說字段類型不對。這時候就需要顯式的手動映射”message” : {“type” : “string”}。如何注冊一個特殊的映射詳見鏈接。
當你使用基於時間的目錄名時,在配置文件里創建索引模板可能更適合一點。詳見鏈接。除去你的映射,你海可以定義其他目錄屬性,比如分片數等等。
在映射中,你可以選擇壓縮文檔的_source。這實際上就是整行日志——所以開啟壓縮可以減小索引大小,而且依賴你的設定,提高性能。經驗值是當你被內存大小和磁盤速度限制的時候,壓縮源文件可以明顯提高速度,相反的,如果受限的是CPU計算能力就不行了。更多關於source字段的細節詳見鏈接。
默認情況下,除了給你所有的字段分別創建索引,elasticsearch還會把他們一起放進一個叫_all的新字段里做索引。好處是你可以在_all里搜索那些你不在乎在哪個字段找到的東西。另一面是在創建索引和增大索引大小的時候會使用額外更多的CPU。所以如果你不用這個特性的話,關掉它。即使你用,最好也考慮一下定義清楚限定哪些字段包含進_all里。詳見鏈接。
刷新間隔
在文檔被索引后,Elasticsearch某種意義上是近乎實時的。在你搜索查找文檔之前,索引必須被刷新。默認情況下,目錄是每秒鍾自動異步刷新的。
刷新是一個非常昂貴的操作,所以如果你稍微增大一些這個值,你會看到非常明顯提高的插入速率。具體增大多少取決於你的用戶可以接受到什么程度。
你可以在你的index template里保存期望的刷新間隔值。或者保存在elasticsearch.yml配置文件里,或者通過(REST API)[http://www.elasticsearch.org/guide/reference/api/admin-indices-update-settings.html]升級索引設定。
另一個處理辦法是禁用掉自動刷新,辦法是設為-1。然后用REST API手動的刷新。當你要一口氣插入海量日志的時候非常有效。不過通常情況下,你一般會采用的就是兩個辦法:在每次bulk插入后刷新或者在每次搜索前刷新。這都會推遲他們自己本身的操作響應。
Thrift
通常時,REST接口是通過HTTP協議的,不過你可以用更快的Thrift替代它。你需要安裝transport-thrift plugin同時保證客戶端支持這點。比如,如果你用的是pyes Python client,只需要把連接端口從默認支持HTTP的9200改到默認支持Thrift的9500就好了。
異步復制
通常,一個索引操作會在所有分片(包括復制的)都完成對文檔的索引后才返回。你可以通過index API設置復制為異步的來讓復制操作在后台運行。你可以直接使用這個API,也可以使用現成的客戶端(比如pyes或者rsyslog的omelasticsearch),都會支持這個。
用過濾器替代請求
通常,當你搜索日志的時候,你感興趣的是通過時間序列做排序而不是評分。這種使用場景下評分是很無關緊要的功能。所以用過濾器來查找日志比用請求更適宜。因為過濾器里不會執行評分而且可以被自動緩存。兩者的更多細節參見鏈接。
批量索引
建議使用bulk API來創建索引它比你一次給一條日志創建一次索引快多了。
主要要考慮兩個事情:
- 最佳的批量大小。它取決於很多你的設定。如果要說起始值的話,可以參考一下pyes里的默認值,即400。
- 給批量操作設定時器。如果你添加日志到緩沖,然后等待它的大小觸發限制以啟動批量插入,千萬確定還要有一個超時限制作為大小限制的補充。否則,如果你的日志量不大的話,你可能看到從日志發布到出現在elasticsearch里有一個巨大的延時。