概要
elastic社のブログに「Little Logstash Lessons: Handling Duplicates」という内容があがっています。
Google翻訳のお力を頂戴して、日本語で内容を確認したその結果です。
結論
elasticsearchにoutputするとき、IDが明示的に指定されていないと、elasticsearch側でIDが採番される。
これが重複して登録する元になっている。
なので、fingerprint filterを使って以下のようにアプローチすると良い。
ともにfingerprintを使うのは同じ。
- 同一の中身のものは、同一のものとして扱いたいとき
- 同じ内容のものは同じIDになるようにし、その値をDocumentのIDとする
- 1回のイベントで送信したものは再送されたとしても、同一のものとして扱いたいとき
- イベントごとにUUIDを生成し、その値をDocumentのIDとする
input {
stdin {}
}
filter {
fingerprint {
source => "message"
target => "[@metadata][fingerprint]"
method => "MURMUR3"
}
}
output {
elasticsearch {
hosts => "example.com"
document_id => "%{[@metadata][fingerprint]}"
}
}
試した環境
product | version |
---|---|
Logstash | 5.4.1 |
なお、logstashの出力結果にホスト名がありますが、記事用に書き換えたものです。
同一内容のものの重複を避ける
stdoutによる確認
まずは、記事にあった内容でそのまま確認します。
[@metadata][fingerpring]に出力していると、metadata => trueにしていないとstdoutで確認できないため、便宜的にfingerprintという項目にfilter結果を入れるように変更します。
input {
stdin {}
}
filter {
fingerprint {
source => "message"
target => "fingerprint"
method => "MURMUR3"
}
}
output {
stdout {
codec => rubydebug
}
}
もし、targetを[@metadata][fingerprint]にしている場合なら、rubydebugにmetadata=>trueを足しましょう。
//略
filter {
fingerprint {
source => "message"
target => "[@metadata][fingerprint]"
method => "MURMUR3"
}
}
output {
stdout {
codec => rubydebug {
metadata => true
}
}
}
aiueoと入力した場合の結果がこちら。fingerprintのところを見てください。
もし、fingerprintの項目をIDに指定していたとしたら、aiueoというmessageを持つものは、IDがすべて4063197173となり、
2回、3回、n回送っても、IDが重複している限り1件のデータにしかならない、ということでしょう。
{
"@timestamp" => 2017-06-06T06:44:48.590Z,
"@version" => "1",
"host" => "UCC-COFFEE-110YEN",
"fingerprint" => 4063197173,
"message" => "aiueo\r"
}
関数を変える
MURMUR3でなく、MD5がいいんや、という場合は、methodを変更します。
input {
stdin {}
}
filter {
fingerprint {
source => "message"
target => "fingerprint"
method => "MD5"
key => "hogehoge"
}
}
output {
stdout {
codec => rubydebug
}
}
同じようにaiueoと入れた結果がこちら。
{
"@timestamp" => 2017-06-06T06:50:35.501Z,
"@version" => "1",
"host" => "UCC-COFFEE-110YEN",
"fingerprint" => "03944d6aa32124dc928257becfc40299",
"message" => "aiueo\r"
}
methodで、SHA1やMD5を使う場合は、keyオプションが必要です。
If you are using any of the cryptographic hash functions algorithms (like SHA1, MD5), it is required to provide a key option. The key can be any arbitrary string which is used to compute the HMAC.
もし、keyを指定せずにlogstashを実行した場合は、次のエラーメッセージを含んだ文字列が出力されて終了します。
"Cannot register filter fingerprint plugin. The error reported is:
Key value is empty. Please fill in an encryption key"
keyは設定するようにしましょう。
fingerprint生成元の指定
今回はsource => "message"
としていたため、messageに入っている文字列から生成していました。
sourceはarrayで指定できるため、複数の項目から値を生成したい場合も可能です。
複数の列が集まってPrimary Keyを作っているDBテーブルのようなものをイメージすればよいと思います。
たとえば、company_cd, code, parameterのようなもので1意にしたい、ということであれば
source => ["company_cd", "code", "parameter"]
のような書き方になるでしょう。
もし、任意の項目ではなく、すべての項目の文字列を1つの文字列のように連結したとして、そこからfingerprintを生成したい、ということであれば、concatenate_sources => "true"
を設定してやればよいでしょう。
input {
stdin {}
}
filter {
fingerprint {
#source => "message"
concatenate_sources => "true"
target => "fingerprint"
method => "MD5"
key => "hogehoge"
}
}
output {
stdout {
codec => rubydebug
}
}
先と同じようにaiueoと入れた場合でも、結果が変わっていることがわかります。
{
"@timestamp" => 2017-06-06T06:55:36.683Z,
"@version" => "1",
"host" => "UCC-COFFEE-110YEN",
"fingerprint" => "3029457907e46196f8510cccfa1ff3ba",
"message" => "aiueo\r"
}
不慮の重複を避ける
Logstashが何らかの影響で処理中に停止し、キューに入ったものが2回送られてしまうようなときを想定する。
少なくとも1回は送信されるけど、まれに2回送信されるかもね、というのはAWSのLambdaでも聞いたような気がします。
input {
stdin {}
}
filter {
fingerprint {
source => "message"
target => "generated_id"
method => "UUID"
}
}
output {
stdout {
codec => rubydebug
}
}
このようにして、aiueoと2回送信してみます。1回目と2回目で同じ文字列を送っているのに、異なるgenerated_idとなっていることが確認できました。
generated_idをdocument_idとしておけば、キューが2回送信されたとしても重複しなくて済む、ということですね。
aiueo
{
"@timestamp" => 2017-06-06T07:11:40.978Z,
"@version" => "1",
"host" => "UCC-COFFEE-110YEN",
"message" => "aiueo\r",
"generated_id" => "647943f7-1cb2-40f1-9e46-471a641f1651"
}
aiueo
{
"@timestamp" => 2017-06-06T07:11:42.332Z,
"@version" => "1",
"host" => "UCC-COFFEE-110YEN",
"message" => "aiueo\r",
"generated_id" => "7d5e0691-b37c-4df1-82b5-3968b4bdbc29"
}
終わりに
As you've seen in this post, the fingerprint filter can serve multiple purposes and is a plugin you should familiarize yourself in the Logstash ecosystem. Take a stab at using this filter and let us know what you think!
fingerprint filterはいろいろ使えますよ、と。
もっと起動が早くなればいうことなしなんだけどな。
参考文献