ようへいの日々精進XP

よかろうもん

2017 年 04 月 13 日(木)

ジョギング

日課

  • (腕立て x 30 + 腹筋 x 30) x 3

なんか

終日バタバタしていた。

意図的ではもちろん無いが、潜在的なバグを作ってしまって申し訳ない気持ちで一杯。他にも色々。

気を引き締めつつ、気負わずやっていきたいと思う。

Datadog APM の Python 用クライアント dd-trace-py をざっくりチュートリアルする 〜 Elasticsearch(Amazon Elasticsearch Service) 編 〜

引き続き

github.com

を弄っています。

Elasticsearch でも APM

Elasticsearch でも簡単に始めることが出来ます。もちろん、Amazon Elasticsearch Service でも無問題(IAM の処理が必要となる場合があります)です。尚、dd-trace-py については導入済みという体で進めます。

本記事作成時の環境

本記事を書くにあたり利用した環境は以下の通りです。

$ python --version
Python 2.7.13

$ pip list --format=columns | egrep 'elasticsearch|ddtrace'
ddtrace           0.8.0
elasticsearch     5.3.0

尚、Amazon Elasticsearch Service のアクセスポリシーは IP アドレスによるアクセス制御で利用します。

Python から Elasticsearch を扱う場合

以下のモジュールを利用します。

github.com

Elastic 謹製です。

サンプルアプリケーション

今回は Elasticsearch に読み込ませた 20 万件程度のレストランデータを検索するコマンドラインツールを作ってみたので、そのコマンドラインツールを dd-trace-py を利用して各処理を追跡して可視化してみたいと思います。

gist.github.com

超ざっくりで Elasticsearch のクエリチューニングは一切行っていませんが、一応、以下のように --name--location オプションで指定したキーワードを含むレストランのリストがダーッと標準出力に表示されます。

$ python restaurant-search.py --name '焼き鳥' --location '福岡' 2> /dev/null
焼き鳥 一郎 | 福岡市博多区美野島2-11-14 |
焼き鳥の屋台 花山 | 福岡市東区箱崎1 |
焼き鳥 たかつ 三苫店 | 福岡市東区三苫1-16-44 |
焼き鳥 木鶏 | 福岡市中央区平尾4-5-15日之出第2平尾ビル |
炭火焼き鳥 ちびっこ大将 | 福岡市中央区高砂2-11-33北村コーポ 1F |
焼き鳥 いわた | 福岡市中央区渡辺通5-24-37レジデンス江崎 2F |
博多水炊きと焼き鳥 鳥善 | 福岡市中央区薬院2-15-2ルミエール薬院1F |

ちなみに、レストランデータは[こちら(https://github.com/livedoor/datasets)のデータを利用させて頂き、stream2esAmazon Elasticsearch Service に放り込んでいます。

Patch

以下のように elasticsearch-py にパッチを当てるだけで Elasticsearch へのクエリを追跡出来るようになります。

from ddtrace import Pin, patch, patch_all
patch(elasticsearch=True)

ソースコードを大幅に手をいれる必要が無いのが嬉しいですね。

tracer.wrap

今回は Elasticsearch へのクエリ以外に、検索処理を担う関数をはじめ、スクリプトの各種関数についてもパフォーマンスをトレースしてみたいと思いますので、tracer.wrap を利用してみたいと思います。

tracer.wrap は関数全体をトレースするデコレータで、以下のように関数の上にちょこんとのっけるだけで、関数の処理結果を Datadog に送信することが出来るようになります。

...
@tracer.wrap('scroll_index', service='sample-app')
def scroll_index(scroll_size, sid):
    try:
        while (scroll_size > 0):
            page = es().scroll(scroll_id=sid, scroll='2m')
            sid = page['_scroll_id']
            scroll_size = len(page['hits']['hits'])
            output(page['hits']['hits'])
    except Exception, e:
        print e
...

ちなみに、デコレータとは対象となる関数をいじることなく、その関数の挙動にてを加える手法という認識で、上記だと scroll_index(scroll_size, sid): という関数に対して、@tracer.wrap という関数でデコレート(装飾)することになります。

さて、今日は何処で呑もうかな、何を食べようかな

やっぱもつ鍋ばい

もつ福岡 で検索してみます。

$ python restaurant-search.py --name 'もつ' --location '福岡' 2> /dev/null
もつもつ天神店 | 福岡市中央区天神335久保田ビル2F |
もつ壙 | 福岡市博多区中洲3-3-3 |
...
...
二十四 永徳屋 博多もつ鍋 | 福岡市博多区美野島1-4-32松永ビル1F |

さすが、もつ鍋王国の博多です。

f:id:inokara:20170412194116p:plain

span = tracer.current_span()
span.set_tag('name', unicode(name, 'utf-8', 'ignore'))

上記のように span.set_tag で Span に対して任意のタグを付与することが出来ます。

福岡で焼肉食べたいばってん、禁煙の席があるといいねえ

もつ福岡 そして 禁煙 で検索します。

$ python restaurant-search.py --name '焼肉' --location '福岡' --keyword '禁煙' 2> /dev/null
焼肉処 國 | 福岡市南区野間2-7-13ヴィラージュ野間 1F | 席数 25席 (掘りごたつ4つとカウンター5席)   駐車場 無  予約 予約可  貸切 可 (20人以下可)   禁煙・喫煙 全面喫煙可  カード 不可

一軒しかヒットしないのは寂しいですが、以下のように検索に利用したキーワードが span のタグとして確認することが出来ます。

f:id:inokara:20170412194714p:plain

Elasticsearch の検索が関数の殆どの時間を使っていることがひと目で判ります。

ということで

dd-trace-py を使うことで、アプリケーションの関数毎のパフォーマンスやデータベースへのアクセス時間ソースコードに殆ど手を加える事無く Datadog で監視出来るというのは嬉しい限りです。

小ネタ道場一本勝負 〜 俺にその JSON を一行でくれよ 〜

その JSON を…

{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "name": "name"
          }
        },
        {
          "term": {
            "description": "keyword"
          }
        },
        {
          "term": {
            "address": "location"
          }
        }
      ]
    }
  }
}

一行で欲しい時がある。

ということで、一本

jq の -c オプションを使えば一瞬で。

$ echo '{
>   "query": {
>     "bool": {
>       "must": [
>         {
>           "term": {
>             "name": "name"
>           }
>         },
>         {
>           "term": {
>             "description": "keyword"
>           }
>         },
>         {
>           "term": {
>             "address": "location"
>           }
>         }
>       ]
>     }
>   }
> }' | jq -c
{"query":{"bool":{"must":[{"term":{"name":"name"}},{"term":{"description":"keyword"}},{"term":{"address":"location"}}]}}}

意図した通りに一行で頂きました。

{"query":{"bool":{"must":[{"term":{"name":"name"}},{"term":{"description":"keyword"}},{"term":{"address":"location"}}]}}}

ありがとう。

あざっした

$ jq --version
jq-1.5

$ jq --help
jq - commandline JSON processor [version 1.5]
Usage: jq [options] <jq filter> [file...]

        jq is a tool for processing JSON inputs, applying the
        given filter to its JSON text inputs and producing the
        filter's results as JSON on standard output.
        The simplest filter is ., which is the identity filter,
        copying jq's input to its output unmodified (except for
        formatting).
        For more advanced filters see the jq(1) manpage ("man jq")
        and/or https://stedolan.github.io/jq

        Some of the options include:
         -c             compact instead of pretty-printed output;
         -n             use `null` as the single input value;
         -e             set the exit status code based on the output;
         -s             read (slurp) all inputs into an array; apply filter to it;
         -r             output raw strings, not JSON texts;
         -R             read raw strings, not JSON texts;
         -C             colorize JSON;
         -M             monochrome (don't colorize JSON);
         -S             sort keys of objects on output;
         --tab  use tabs for indentation;
         --arg a v      set variable $a to value <v>;
         --argjson a v  set variable $a to JSON value <v>;
         --slurpfile a f        set variable $a to an array of JSON texts read from <f>;
        See the manpage for more options.

2017 年 04 月 10 日(月)

終日

頭痛。後頭部あたりが痛い。背中の張りに引っ張られているような痛み。

色々とガタが…

奥さん

体調不良でお休み。

夕方には少し元気になったようで夕飯を作ったりしていたので一安心。

2017 年 04 月 08 日(土)

ジョギング

日課

  • (腕立て x 30 + 腹筋 x 30) x 3

原鶴温泉

こう言っちゃ失礼だけど、自分の中でマイナー温泉郷だった原鶴温泉だったけど、良い意味で裏切られた。

www.harazuru-hanamizuki.jp

奥さんを癒やしてあげたかったので、一泊ゆっくりすることにした。

ご飯良し、お湯まあまあ良し。明日は筑後川沿いをジョギングする予定。