elasticsearchのindexを整理するcuratorのactionファイルを整理した話
これは何
elasticsearchのindexを削除するときにはcuratorを使うと思うが、そのactionファイルがわかりにくく、大きくなりがちだったのでメモ。 curator はver 4での記法(ver3だとちょっと違うみたいなので注意)
curator action fileの基本の書き方
1から順番に実行される。
actions: 1: action: delete_indices description: "delete application log indices" options: disable_action: False ignore_empty_list: True filters: - filtertype: pattern kind: prefix value: "application." # elasticsearchのindex名と"kind","value"設定が対応するようにする exclude: False - filtertype: age source: creation_date direction: older timestring: '%Y.%m.%d' unit: days unit_count: "30" # 30日残す設定 2: action: delete_indices description: "delete indices" options: disable_action: False ignore_empty_list: True filters: - filtertype: pattern kind: prefix value: "application." exclude: True # ここでexcludeしておかないと30日保存したいのに10日までになってしまう - filtertype: kibana exclude: True # kibanaを使っている場合には入れたほうがよい。.kibanaファイルが消えて、kibana indexを毎回登録しないといけなくなる。 - filtertype: age source: creation_date direction: older timestring: '%Y.%m.%d' unit: days unit_count: 10
削除日数を細かく制御したい場合(ansible templateで解決)
上の例の1の記述のところみたいなのを並べて、さらに2のexcludeにも突っ込んでいかないといけない。コード量が増えて管理しづらい。 ansibleで配置するなら以下のようにすればvarsのリストに追加するだけで簡単。
- varsで以下のように設定する
CURATOR_DELETE_LIST: - { TARGET: "application." , DAYS: "30" } - { TARGET: "httpd.error." , DAYS: "30" } - { TARGET: "httpd.access.hoge." , DAYS: "7" } - { TARGET: "httpd.access.hoge." , DAYS: "7" }
- loopでまわす
actions: {# 明示的な削除対象のためのブロック-#} {% for t in CURATOR_DELETE_LIST %} {{ loop.index }}: action: delete_indices description: "delete {{ t.TARGET }} indices" options: disable_action: False ignore_empty_list: True filters: - filtertype: pattern kind: prefix value: "{{ t.TARGET }}" exclude: False - filtertype: age source: creation_date direction: older timestring: '%Y.%m.%d' unit: days unit_count: "{{ t.DAYS }}" {% endfor %} {# .kibana を除くその他の index は 10 日間保持。最後のactionになるように99としておく。 #} 99: action: delete_indices description: "delete indices" options: disable_action: False ignore_empty_list: True filters: {% for t in CURATOR_DELETE_LIST %} - filtertype: pattern kind: prefix value: "{{ t.TARGET }}" exclude: True {% endfor %} - filtertype: kibana exclude: True - filtertype: age source: creation_date direction: older timestring: '%Y.%m.%d' unit: days unit_count: 10
もっとまとめて綺麗にできるかも。でもまあ役割ごとにブロックで分けれたからよし。
memcachedのサイズ別データ数のカウント
これは何
memcachedからredisへ移行したいので、redisのベンチマークを取っていたが、その時にmemcachedに保存されているデータがどれくらいのサイズがどれくらいの量で出現するのか確認した。その話を適当にまとめておく。
chunkサイズとslabについて
参考: http://gihyo.jp/dev/feature/01/memcached/0002
memachedはメモリのフラグメンテーションを防ぐために slab allocator というのを使っているっぽい。単にmalloc と freeを使ってメモリを扱うとばらばらになってしまう。確保したメモリをいろいろなサイズの塊(chunk)にわけて同じサイズの塊をクラスとしてひとまとまりにする。stats itemの出力はどうもこのchunk別に別れている模様。
class別個数カウント
$ echo "stats items" | nc localhost 11211 | grep number STAT items:1:number 6 STAT items:2:number 4990 STAT items:3:number 1 STAT items:4:number 39 STAT items:5:number 160 STAT items:6:number 3 STAT items:7:number 17 STAT items:8:number 19 STAT items:9:number 46 STAT items:10:number 1 STAT items:11:number 5326 STAT items:12:number 1397 STAT items:13:number 60 以下略
このコマンドは↓でもよい
$ echo "stats slabs" | nc localhost 11211 | grep used_chunk
classのサイズを確認する
上からサイズ順になっている。
$ echo "stats slabs" | nc localhost 11211 | grep chunk_size STAT 1:chunk_size 96 STAT 2:chunk_size 120 STAT 3:chunk_size 152 STAT 4:chunk_size 192 STAT 5:chunk_size 240 STAT 6:chunk_size 304 STAT 7:chunk_size 384 STAT 8:chunk_size 480 STAT 9:chunk_size 600 STAT 10:chunk_size 752 STAT 11:chunk_size 944 STAT 12:chunk_size 1184 STAT 13:chunk_size 1480 以下略
トータル個数とか一定サイズ以上のものとか
$ echo "stats slabs" | nc localhost 11211 | grep used_chunk | awk 'BEGIN {num = 0};{ sum =+ sum + $3} END {print sum }'
大きいサイズの個数が知りたいななど。例えばclass 19以上のもの(size 5kでの区切りで見たやつ)
$ echo "stats slabs" | nc localhost 11211 | grep used_chunk | egrep "(STAT 19|STAT [2-4][0-9])" | awk 'BEGIN {num = 0};{ sum =+ sum + $3} END {print sum }'
redisとmemcachedのベンチマークをmemtier-benchmarkで取る
これは何
redisとmemcachedのベンチマークを memtier-benchmark というツールで取った。 ざっくりまとめておく。
memtier-benchmark と redis-benchmark の比較
主にmemtier-benchmarkのメリット。redis-benchmarkにできないこと。
- redis, memcache の両方のプロトコルを喋れる(redis-benchはredisのみ)
- SET/GETの重み付けができる(redis-benchはそれぞれ別に全力で投げる)
- keyとvalueサイズを変えられて(redis-benchはkeyサイズを変えるのが大変。valueサイズはどちらもオプションで変えられる。)
memtier-benchmark のインストール
概ねREADMEどおりにできた。 インストールしたlibevent-2.0がmemtier-benchmark実行時に見つからなかったので雑にlinkして見えるようにした(多分良い解決策ではないが、使い捨て負荷試験環境なので良し)。
sudo ln -s /usr/local/lib/libevent-2.0.so.5 /usr/lib64/libevent-2.0.so.5
コマンド
memtier_benchmark -p 6379 -P redis --threads 4 -c 250 --test-time=10 --ratio=1:10 --data-size-list=1000:60,5000:30,100000:10 --key-prefix=memtier-memtier-memtier- --key-maximum=100000
実際にやったコマンドとは異なるが、サンプルとして書いておく。以下雑な説明
fluent-plugin-ping-messageプラグインを最新のを入れるとtd-agentがunstable versionになるためバージョン指定する話
これは何
https://rubygems.org/gems/fluent-plugin-ping-message/ という Fluentd の plugin を最新化すると、同時に td-agent 本体も unstable な最新の 0.14 系にあがってしまい、ログ転送がたまにできなくなる事象が発生する。 その対策。
原因
この現象はpluginの依存するfluentdのバージョンが指定されているので、gemで最新のplugin version1.0.0が入るとfluentdも v0.14が必要になり、強制的にあげられてしまうため。 参考: https://github.com/tagomoris/fluent-plugin-ping-message
対策
ansibleのtasksで書くならこんな感じ。-vで指定する。
- name: add fluent-plugin-ping-message shell: td-agent-gem install fluent-plugin-ping-message -v {{ FLUENT_PLUGIN_PING_MESSAGE_VERSION }}
stableなtd-agentのバージョンは? どこで確認する?
http://www.fluentd.org/download
- stable v0.12 系
- experimental version が v0.14となっている。
td-agent本体 version確認方法
$ which td-agent /usr/sbin/td-agent $ td-agent --version td-agent 0.12.29
plugin version確認方法
td-agent-gemで入れているので listコマンドから確認
$ td-agent-gem list | grep ping fluent-plugin-ping-message (1.0.0, 0.2.0)
左が新しいもの、右が古いversionっぽい。gemで入れると古いバージョンも残るらしい。 $ td-agent-gem list | grep ping fluent-plugin-ping-message (0.2.0)
入れなおし方法
- sudo yum remove td-agentを実行する
- rm -rf /opt/td-agentを実行して残存プログラムを完全消去する。これをやらないと/opt/td-agentにプログラム本体がいるっぽく yumで再インストールしてもversionが新しいプログラムのままになる。
- td-agent再インストール
実験
plugin入れる前
$ td-agent --version td-agent 0.12.31
入れてみる
$ sudo td-agent-gem install fluent-plugin-ping-message Fetching: strptime-0.1.9.gem (100%) Building native extensions. This could take a while... Successfully installed strptime-0.1.9 Fetching: serverengine-2.0.4.gem (100%) Successfully installed serverengine-2.0.4 Fetching: msgpack-1.1.0.gem (100%) Building native extensions. This could take a while... Successfully installed msgpack-1.1.0 Fetching: fluentd-0.14.13.gem (100%) Successfully installed fluentd-0.14.13 ★ここで fluentd 0.14 を入れている。 Fetching: fluent-plugin-ping-message-1.0.0.gem (100%) Successfully installed fluent-plugin-ping-message-1.0.0 Parsing documentation for strptime-0.1.9 Installing ri documentation for strptime-0.1.9 Parsing documentation for serverengine-2.0.4 Installing ri documentation for serverengine-2.0.4 Parsing documentation for msgpack-1.1.0 Installing ri documentation for msgpack-1.1.0 Parsing documentation for fluentd-0.14.13 Installing ri documentation for fluentd-0.14.13 Parsing documentation for fluent-plugin-ping-message-1.0.0 Installing ri documentation for fluent-plugin-ping-message-1.0.0 Done installing documentation for strptime, serverengine, msgpack, fluentd, fluent-plugin-ping-message after 8 seconds 5 gems installed
$ td-agent --version td-agent 0.14.13
haproxy設定の自分メモ(redisのrevproとして)
これは何
redis+sentinelの前段にhaproxyを置いてクライアントがあんまりnode poolを意識しなくてもよさそうな感じにしたい。 devだけで適用して本番には適用していないので甘いところはあるかも。
方針
redis slaveにgetを負荷分散したりするほど負荷は高くない系に使えるかも。 常にmasterに接続しに行き、slaveは待機系。
設定ファイル
ansible templateの形。
global {# chroot内で動いているため/dev/logへアクセスできない。そのためUDP経由でrsyslogにログを渡す。-#} log 127.0.0.1 local2 chroot {{ HAPROXY_JAIL_DIR }} user {{ HAPROXY_USER }} group {{ HAPROXY_GROUP }} daemon {# maxconn: redisで設定しているものより大きければよい。このレイヤでは特に制限はかけない。 -#} maxconn 10000 {# stats: haproxyのステータスを取れるようにするための設定 -#} listen stats {# bind: ポート9000への外部からの経路はないが念のためback側からのみ疎通可能としておく。-#} bind :9000 interface eth0 mode http stats enable stats uri /haproxy_stats {# refresh: stats画面の自動リフレッシュを有効にする -#} stats refresh 10 defaults mode tcp log global option dontlognull {# retries: バックエンドサーバへ接続失敗した時の再試行回数-#} retries 3 {# timeout queue: maxconnを超えたリクエストはキューに入る。そのキューに入った接続を開放するまでの時間。そんなに待たせても意味が無いのであまり大きな値じゃなくてよい。 -#} timeout queue 10s {# timeout connect: haproxyのbackendへの接続のタイムアウト。近いネットワークにいれば基本的に短い時間で接続できるはず。 -#} timeout connect 5s {# timeout check: コネクションが確立したあとの追加のヘルスチェックのタイムアウト。これに時間がかかるということはラグの大きなサーバなので、長い時間待つ必要はない。-#} timeout check 5s {# timeout client-fin/server-fin: 正しく接続断しなかった場合に切る(こちらからFIN送信したがクライアントがFINを送ってこなかった場合)。FIN_WAIT状態が続くのを防ぐ。 -#} timeout client-fin 10s timeout server-fin 10s {# その他入れない設定について。いれるのが推奨のようなので要検討。 * timeout client: 非活性なクライアントからの接続を切る設定。redis設定に合わせて設定しない。 * timeout server: haproxyから非活性backendへの接続を切る時間。redis設定に合わせて設定しない。 -#} frontend main bind *:5000 default_backend myredis backend myredis {# balance: どれか1台だけがコネクションを受け付ける設定(first)。id設定があれば一番値が小さいもの。なければリストの1番上から優先される。負荷分散よりも1台のmasterにキャッシュがのることを優先する。 -#} balance first {# 通常時のヘルスチェック間隔はredisのマスター昇格のタイムスケールにあわせて秒単位でよい。haproxyのreload直後などでヘルスチェックをしていない場合には即座に行う(fastinter)。-#} {% for srv in HAPROXY_BACKEND_LIST -%} server redis{{ loop.index }} {{ srv }} check inter 1s fall 2 rise 1 fastinter 10ms {% endfor %} option tcp-check tcp-check connect tcp-check send info\ replication\r\n tcp-check expect string role:master tcp-check send QUIT\r\n tcp-check expect string +OK
ちなみに rsyslog設定のansible taskはこんな感じ
# haproxyのログ出力のためのrsyslog設定 - name: enable UDP log acceptance for rsyslog for haproxy lineinfile: dest: "/etc/rsyslog.conf" line: "{{ item }}" with_items: - "$ModLoad imudp" - "$UDPServerRun 514" - "local2.* {{ HAPROXY_LOG_DIR }}/haproxy.log"
redis設定について自分メモ
これはなに
redis設定をした時の検討項目。 devで設定したのみでまだ本番で使っていないのであまいところはあるかも。
設定diff
以下は redis-3.2.8 に同梱されていた設定ファイルとplaybook template とのdiff。
diff /tmp/redis.conf roles/install_redis/templates/redis.conf.j2 1c1,3 < # Redis configuration file example. --- > # USAGE: {{ item.USAGE }} > # Redis configuration file. > # This configuration is based on redis-3.2.8 default configuration file. 61c63,64 < bind 127.0.0.1 --- > {# bind: 特に認証はかけない。やるならサーバが居るネットワークセグメントごとに裏からのみ疎通できるようにするなどの設定をいれる。 -#} > # bind 80c83,84 < protected-mode yes --- > {# protected-mode: キャッシュサーバはインターネットに直接露出しなければ切っておいてもよいかもしれない -#} > protected-mode no 84c88,89 < port 6379 --- > {# port: 同一サーバ内に別ポートで複数インスタンスを立ち上げることができるようにしておきたい -#} > port {{ item.PORT }} 93c98,99 < tcp-backlog 511 --- > {# tcp-backlog: これと一緒にsomaxconnもsysctlで設定しておく必要がある。TCPの接続要求を格納するキューの最大長なので、front系サーバapacheがある程度詰まっても大丈夫な値にしておくのがよさそう -#} > tcp-backlog 2500 104a111 > {# timeout: idle状態のコネクションはタイムアウトさせない(デフォルト設定)。アプリケーションが側できちんと切断処理がされていれば問題にならないはず-#} 127a135 > {# daemonize: 直接redis-serverコマンドにこの設定ファイルを食わせて起動した場合にはデバッグのためにdaemonize noでよい。systemctlで起動した場合にはこの設定に関わらずデーモン化される -#} 150c158,159 < pidfile /var/run/redis_6379.pid --- > {# pidfile: 一応設定しているが、systemdではpidファイルは不要 -#} > pidfile /var/run/redis_{{ item.PORT }}.pid 163c172,173 < logfile "" --- > {# logfile: redisユーザに権限があるディレクトリにログを吐くようにしておく。ローテートも忘れずに。redisはログを吐くごとにファイルを開き直すのでSIGHUPなどは不要。 -#} > logfile "{{ REDIS_LOG_DIR }}/redis.log" 177a188 > {# database: keyspaceが独立したdatabaseを何個にするか。使えるDatabaseがの数が大きくてもデフォルトは0が使われるので細かい値はなんでもよさそう。dev, productionとかで使う用途を想定しているみたい。-#} 201c212,216 < --- > {# save: redisが死んでて復旧した時にRDBには古いデータが残っている。しかしexpireは実時間基準なのできちんと古いデータは消えておいてくれる。 > RDBを取る時に親プロセスがやるのは子プロセスをforkさせるだけなので、親インスタンスにdisk I/Oが発生して待ちになることはないとのこと。あまりにもデータが大きいもしくはCPUがいまいちな場合にはforkに時間かかるのでclientへのレスポンス遅れることもあるらしい。 > RDBの方がAOFをよりも起動が早く、データサイズも小さいのがメリット。マスタデータはredisには無ければ厳密に永続化を考えなくても良い。パフォーマンスが落ちない程度に使う方針。 > 設定はデフォルトで問題なさそうならそのまま。 > -#} 219c234,235 < stop-writes-on-bgsave-error yes --- > {# stop-writes-on-bgsave-error: persistentが止まるよりもwriteが止まるほうが不都合。TODO 適切な監視はほしい。 -#} > stop-writes-on-bgsave-error no 224a241 > {# rdbcompression: 多少CPUを使っていても圧縮しておいてくれた方が良い。あまりにCPU不可が高くなりそうなら変えても良い。 -#} 233a251 > {# rdbchecksum: 10%程度の性能劣化はあるがRDBファイルの破損の検知は入れたままでもよさそう。 -#} 247c265,266 < dir ./ --- > {# dir: ファイル名はデフォルトで良いが、保存先は適切なpermissionの場所に配置しなければならない。-#} > dir {{ REDIS_DATABASE_DIR }} 265c284,288 < # slaveof <masterip> <masterport> --- > # slaveof <masterip> <masterport> > {# slaveof: 設定に書かないでDBと同じようにコマンドで指定するのもあり。ただしmysqlの場合にはchange master toではその設定がファイルに保存される。redisの場合には設定に書いてないと再起動時に消えてしまうと思われる。意図せず消えてしまうか、意図しないmasterを向いているかで比較的後者の方が事故が少ないと考えてファイルに記載する。原則としてシステムに組み込むときにはmasterノードがどれか確認してから組み込むのがよい。 -#} > {% if REPL_NODE=="slave" %} > slaveof {{ REDIS_MASTER_NAME }} {{ REDIS_MASTER_PORT }} > {% endif %} 284a308 > {# slave-serve-stale-data: レプリケーション遅延で多少古いデータが帰ってしまったとしてもエラーを返すよりマシかもしれない(デフォルト) -#} 300a325,326 > {# slave-read-only: masterとの再同期によりslaveのみに保持されたデータは削除されるのでslaveに一時的に書き込みたいデータを書いておく用途に使える。特に使いたい理由がなければreadonlyのほうがよい(デフォルト)。 > -#} 414c440,441 < slave-priority 100 --- > {# slave-priority: 基本的には変更しないが、仮にmasterにしたくないslaveを作ることになったらansible EXTRA_VARSで0に設定できるようにしておく。-#} > slave-priority {{ REDIS_SLAVE_PRIORITY | default("100") }} 511a539 > {# maxclients: 十分に大きいのでデフォルトのままでよい。pconnect使うならそれを意識して増やしておいたほうがよい。コネクションの数の監視も必要だろう-#} 537a566,570 > {% if ENVIRONMENT == "production" -%} > maxmemory {{ item.MAXMEMORY }} > {% else %} > maxmemory 1G > {% endif %} 592c625 < --- > {# appendonly: redisにはマスタデータは乗らなければ永続化より性能を重視してOffにしておく。 -#} 623,624c656,657 < appendfsync everysec < # appendfsync no --- > # appendfsync everysec > appendfsync no 834a868 > {# slowlog-log-slower-than: デフォルトでも秒に直すと0.01秒なので十分小さいのでそのままでよい。-#} 838a873 > {# slowlog-max-len: ここで設定した以上古いログは消えてしまう。まずはデフォルトで良い。あとで値を上げたければCONFIG SETコマンドを用いて設定できる。ログを見るためにはSLOWLOG GETコマンドを用いる -#} 905a941 > {# notify-keyspace-events: TODO 何かに使えそう。更新されたらPUBされるので他のサーバが更新を検知できる。サーバリストなど。PUBされた時にSUBしているサーバが接続していなければ受け取れないので注意が必要。pub/subを使いつつ、定期的に値を見直すなどを使えば信頼性をあるていど担保できるかもしれない。 -#}
nginxによるgzip圧縮について【技術メモ】
これは何
nginxでproxyするときにgzip圧縮してレスポンスする方法を学んだのでメモ書き。 nginx versionは 1.11.10。
動作確認
レスポンスヘッダに以下のものが含まれる
- Vary: Accept-Encoding
- Content-Encoding: gzip
設定内容
- gzip_buffers 1000 64k ;
- 配信する最大サイズと対応させる。
- 「マスタリングNginx」によれば、bufferが足りないと巨大なファイルは途中で切れてしまう現象が発生するとのこと。デフォルトだと(確か)128kまでしか圧縮できない。
- 実際に使う分だけそのとき割り当てられる。
- gzip_types
- text/html はデフォルト。他のmime typeに対して使うなら追加する。
- gzip_proxied any;
- プロキシしているレスポンスについても必ず圧縮をかける。
- gzip_vary on;
- Accept Encoding に gzip入れていないものについては別のキャッシュが使われる
- gzip_comp_level;
- gzip_disable msie6;
メモ
配信サーバの画像のgzip圧縮しようかと思って調べたけど、そもそもjpegは圧縮されたフォーマットだったのだった。 結局使わなかった設定。