t-suzuki 雑記ノート

主に技術の話

ansibleのget_url moduleでSNIのhttpsサイトからダウンロードが出来ない【問題と解決】

これは何

ansible version 2.2。get_url moduleを使ったときの話。 ターゲットサーバのOSはSL6.8。python 2.6。

結論から言うと

証明書期限切れしていただけでした。ドハマリした。 期限切れしていない正常なダウンロードサイトからのものはpython2.6にpipでライブラリいれたら治っていた。

問題

"msg": "Failed to validate the SSL certificate for hogehoge.org:443. Make sure your managed systems have a valid CA certificate installed. If the website serving the url uses SNI you need python >= 2.7.9 on your managed machine or you can install the `urllib3`, `pyopenssl`, `ndg-httpsclient`, and `pyasn1` python modules to perform SNI verification in python >= 2.6. You can use validate_certs=False if you do not need to confirm the servers identity but this is unsafe and not recommended. Paths checked for this platform: /etc/ssl/certs, /etc/pki/ca-trust/extracted/pem, /etc/pki/tls/certs, /usr/share/ca-certificates/cacert.org, /etc/ansible"}

解決策

提示されている解決策とやってみた内容は以下

  • python 2.6だとurllib3, pyopenssl, ndg-httpsclient, and pyasn1 を入れると治るかも => pipで入れてみたが、この部分のエラーメッセージだけが消えて他は同じ。解決せず
  • python2.7を入れてみる => ソースからビルドして ansible_python_interpreter=/usr/local/bin/python に設定してみた。同じくこの部分のエラーメッセージだけが消えて、解決せず
  • 後の問題は、そもそも正しい証明書が系にインストールされていない? 根が深そうなきがするが・・・

じゃあSNI対応しているwget使うとどうか? => 同じように検証でエラーがでる。SNI対応していて治るなら1個め2個めで治っているはずだしね。 結局、ブラウザでアクセスしてよくよく見てみると、

この証明書の有効期限は 2017年8月2日 18:39 に切れています だった。

※これが起こった日は 2017/8/4 最初にダウンロードリンクを取る時にアクセスしてスルーしていたのだった。ちゃんと真っ赤になっていたのに。「ドメインあっているよなあ」などと思って。

結論

思い込みで時間を無駄にした。 やはり違和感は大切にしよう。後で調べる、と思っていたことがトラブルの元になるので、違和感があったらできるだけ説明がつけられるようにしておこう。

swapが出るDBサーバの vm.swappiness と innodb_flush_metho=O_DIRECT設定 について

これはなに

MySQLサーバでswapが出てレプリケーション遅延が起こっていた。その原因を考えた時のメモ(結構昔だけど、掘り起こして少し整理)。

トラブル発生時の状況

swap 全食いつぶしされていた(swapは8Gの設定)。swap が単に発生したというよりも、swap in/out が沢山あったのが問題。3列目がページイン(swapin)、4列目が ページアウト(swapout) 。単位は kbyte/s。

$ sar -f /var/log/sa/sa16 -B  | grep '11:20' -A 10
11:20:01 AM     19.96   1528.86    227.95      0.23    306.29      0.00      0.00      0.00      0.00
11:30:01 AM     32.78   1060.79    284.00      0.41    418.23     57.04      2.05     53.95     91.29
11:40:01 AM     35.41    918.87    288.44      0.32    613.35    156.52      4.00    154.15     96.03
11:50:01 AM     30.93    931.70    337.14      0.23    635.15    129.01      3.78    125.92     94.82
12:00:08 PM   1090.31  66591.60   1161.96     38.31  18141.11 264214.86 998791.30  17389.23      1.38
12:10:04 PM  16094.34  73548.50   1853.48     65.37  23471.29 248716.54 1527936.86  22704.65      1.28
12:20:05 PM  25803.10  25574.29   2219.17    183.17  13001.47  45104.96  88174.19  12253.92      9.19
12:30:07 PM   6338.98  27665.28   1886.63    201.32   8700.89  42764.03  85559.13   7997.71      6.23
12:40:05 PM   6489.96  22360.17   1541.27    204.05   7111.80  38805.93  31339.39   6642.17      9.47
12:50:01 PM   7012.49  16050.09    730.82     80.87  14578.10  23819.42  35602.05   3570.47      6.01
01:00:01 PM      0.03      1.32     43.08      0.01     28.28      0.00      0.00      0.00      0.00

cpu 使用率 system 30% と I/o wait 20 % くらいでていた。User は数%程度でそこまで大きく変わらず。

対策

swappiness 設定

https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Performance_Tuning_Guide/s-memory-tunables.html  anonymous memory か page cache かどちらを優先するのかの度合。値が低ければ スワップアウトを避ける(anonymous memoryをスワップに出さずに、page cacheをディスクに書き戻すのを優先する)。 DBだと低めの値を設定するのが推奨のよう。 RHEL 6.4 からは swappiness = 0 はさらに強くswapout しないような仕様になっているそうなので注意が必要。Oracle Databaseで10が推奨とのこと。

anonyamous memory って何? page cacheとの関係は?

http://nopipi.hatenablog.com/entry/2015/09/13/181026   無名ページ —>メモリが足りない時スワップアウト(スワップへ退避)され、物理メモリから解放されるページ ファイルページ —> メモリが足りない時ディスク同期し解放されるページ スワップする/しない、の差。 どういうこっちゃ? もうちょっと調べる。

http://enakai00.hatenablog.com/entry/20110906/1315315488
http://mkosaki.blog46.fc2.com/blog-entry-884.html
MemTotal = MemFree + File-backedなメモリ + Anonymousなメモリ + カーネル空間が使うメモリ File-backed(file pageやpage cacheとも)というのは、ディスクからメモリに読み込んだファイルなど、メモリを開放したくなったら、その内容をディスクに書き戻せば開放できるタイプのメモリ。ファイルキャッシュ、バッファ、プロセスのテキスト領域(プログラム本体) 

Anonymousというのはそれ以外のメモリで、メモリを開放したくなったら、Swap領域に書き出さないと開放できないタイプのメモリ。プロセスのメモリ(データ/スタック領域)、共有メモリ、tmpfsとか。

maria DBでのswappiness 推奨設定

https://mariadb.com/kb/en/mariadb/configuring-swappiness/   swappiness = 1 がよい。 そもそも メモリがswapであることを想定したアルゴリズムではない、とのこと。mysql でも同様か? 値の参考には出来そう。

結局どのような設定にすべきか?

innodb buffer pool 内に書かれているものは、ディスクにそのまま書き戻せるものではなくて、検索結果や更新途中の処理のデータが乗っている。つまり、mysqldによって作られたanonymous memoryとして持たれていると思われる。anonymous memory は以下のように確認する。18G ちょっとある(データはトラブルの起こっていない他のDB)。

$ grep anon /proc/meminfo -A 2
Active(anon):   19021848 kB
Inactive(anon):  1724228 kB
Active(file):    1416160 kB
Inactive(file):  1705648 kB

バイナリログ/その他ログなどはfile cacheへ置かれていると考えられ、これらがメモリ内に共存することになる。 ここで swappiness が高い(デフォルト60)だと、file cache とanonymous memory のどちらも物理メモリ上に残そうとするため、物理メモリがあふれるとfile cacheの一部がディスクに戻ると共に、anonymous memoryの一部がswapに書きだされる。kernel の mm/vmscan.c を読むと、fille_prio = 200 - anon_prio (デフォルトなら file:anon = 140 :60)となっており、LRU(使ってないものから追い出す)に基づいて追い出す模様(深くは追えていない)。 一方 swappiness が低い(例えば設定値1の)場合には、anonymous memoryを物理メモリ上に置いておく優先順位が高くなり、file cacheが優先的にディスクに戻される。すなわり、swapは起こりにくくなる。
DBにおいてswap が発生するのと、file cacheが揮発するのとどちらがサーバ全体に有利かという点を考える。innodb buffer pool が swap に書きだされるか、主にその他ログファイルがディスクに戻るかとの違い。

file cache に乗る可能性のあるもの。ログファイルの大きさは innodb_log_file_size = 128M であり、そこまで大きくない。slow query log は(肥大化しているとはいえ)300M 以下。DBサーバにおいてメモリに必ず乗っていて欲しい大きなファイルなどは他にない。他に数G単位のがあるならbuffer pool sizeチューニングの話のところで出てくるはずだし、Active(file)あたりにも現れるはず。テーブルスペースから buffer pool にのせる前にfile cache にのせることがある。この buffer pool にのせる前のfile cache については innodb_flush_method 設定で抑制できそう。
結論: 単に各種ログファイル等が開かれることにより乗った古い file cache がディスクに書き戻されても差支えないと考えれば、swap が出るよりは file cacheに乗っているデータをファイルに戻してもらった方がよい。  

innodb_flush_method = O_DIRECT設定

設定の意味は? https://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html#sysvar_innodb_flush_method   データファイルを開くときには O_DIRECT を用いて、flushするときにはfsync() を用いるというオプション。ただし、fsyncするときもOSはデータキャッシュを行わない。 デフォルトでは innodb データファイルから、一回ファイルシステムキャッシュを経由して innodb buffer pool にデータを読みだす。 O_DIRECT設定をいれると、データファイルから直接buffer pool に読み込むことで、システムによるキャッシュとRDBMSによるキャッシュの重複を無くすという感じ。buffer pool にキャッシュされているデータは、まったく内容が同じというわけではないが役割がかぶるので、それだけを使う。

デメリットはあるのか?

http://d.hatena.ne.jp/sh2/20101205 性能を上げるというよりも、メモリ使用量を制限するというためのものだと考えた方がよさそう。 どういうときに入れてもいいのかという話は 「High Performance MySQL」に書かれていた。https://books.google.co.jp/books?id=JXFuCQAAQBAJ&pg=PA363&lpg=PA363&dq=O_DIRECT+raid+write+back&source=bl&ots=8oVbZYwCdj&sig=4vpbTujup-BfTM0bRACIsnOLcA0&hl=ja&sa=X&ved=0ahUKEwi6qdrEseDMAhVBpJQKHVK9D-4Q6AEIHjAA#v=onepage&q=O_DIRECT%20raid%20write%20back&f=false この設定はOSによるキャッシュは無効化するが、RAIDカードによる read-ahead は無効化しない。O_DIRECT を有効化してかつパフォーマンスを落ちないようにする方法は、RAIDカードによる write-back設定をいれたwrite cache が必要。InnoDBと実際のストレージとの間にバッファがなければ、パフォーマンスは劇的に悪くなる。 弊社で使用しているサーバは write-back 設定を入れてあるはずなので大丈夫(構築時に一応確認するが、大体デフォルトで入っている)。 また、設定を入れるとMysqlを起動した直後のパフォーマンスが悪くなりそう。OSがキャッシュしていれば起動後にdiskから直接読みださなくてよいので早くなる。これは、OS再起動後とかだとどちらにせよOSによるファイルキャッシュも消えていると思うので気にしてもしょうがなさそう。

設定手順

vm.swappiness = 1の設定を入れる
sudo su -
sysctl vm.swappiness # 確認
sudo cp /etc/sysctl.conf /var/tmp/sysctl.conf
sudo vim /etc/sysctl.conf 
 # 末尾に vm.swappiness=1 を追記
diff /var/tmp/sysctl.conf  /etc/sysctl.conf
sudo sysctl -p # 設定を反映
sysctl vm.swappiness # 反映を確認
innodb_flush_method = O_DIRECT の設定をいれる

[mysqld]ブロックの最後にでも以下の記述を追加する

innodb_flush_method=O_DIRECT
mysql restart する

$ sudo service mysql restart

設定確認する
mysql -uroot -p -e "show global variables ;" | grep innodb_flush_method

納期と障害とElasticBeansTalkのお話

さて、納期がありますね。
急いで開発しますね。
リリースしますね。
喜びますね。
お客さん沢山きますね。

・・・(しばしリリースを喜ぶ)

負荷が上がりますね。
詰まりますね。
障害ですね。

こんにちは。ElasticBeansTalkを作ってとあるキャンペーンの特設サイトを構築した話です。

要件的なやつ
  • リリースまで残り10日くらい
  • キャンペーン期間は一ヶ月以下
  • SSLじゃないとダメ(oauthのコールバックの関係)
  • Nodejs, Nginx, 適当なNoSQL

期限的にオンプレでssl証明書買うのは無理だし、ちゃんとしたの買うと短い期間しか使わないのに高い。そしたらクラウドに金払った方が良い。 どうやらAWSACMというやつで高速で証明書発行してhttpsサイト作れるらしいじゃないの。最高。
そしてElasticBeansTalkというやつで高速にELB+EC2(Nginx+Nodejs)+DynamoDB立てられるらしいじゃないですか。

こりゃ楽勝だな。

やったみた
  • ElasticBeansTalk+ACMを使って、サンプルアプリデプロイして動かすまで1日かからず。最高。
  • インフラとしては監視を入れたい。ebextensionsを使ってCloudFormation的なものを書く。ほぼサンプルなのでデプロイすれば動く。楽勝。
  • ↑のものを何が書いてあるのに理解するのに3日くらい(まだ理解仕切れていない)。AWS普段触らない人には辛い。
  • AWSでどれくらいかかるか詳細見積もり(ざっくり見積もりはEC2使うと決めた時点でざっくりとっていたが、インスタンスタイプとかアクセス見積もりとか詳細のやつ)。
  • DynamoDBもサンプルデプロイして半日たたずに動く。なるほど。オートスケールはデフォルトじゃないのか。気をつけないとね。楽勝(嫌な予感。伝えておかないと)。サンプル突っ込んだら動いたことを開発側に伝えて、ドキュメント渡してその後ここを丸投げ。
  • Slack通知もしたいねということで、LamdaのBlueprintとかいうのを使ってSNSからLamda通してSlack通知へ。
  • その他eb設定もebextensionsで管理

slack通知のタスクは残念ながらリリース時間には間に合わなかったけど、アプリ共々動いてるのでリリースはできた。

で、問題は?

リリース後、しばらくしたら5xx返すかクソ重いかになる。
EC2はCPUまあまあ食ってるけど詰まるほどではない。メモリはスカスカ。サーバ内書き込みないからDiskIOなんて起こるはずもない。確かにNodejsなので1プロセスだけ立てててそれが詰まると死ぬのだが、それだったらCPUはりつくのではという感じだし。実際にオートスケールの下限を増やしたが関係なし。
となるとDBだな。 はい。DynamoDB詰まってました。
オートスケールするんじゃないの?

前述した通り、オートスケールはデフォルトではありませんでした。
自分で手作業で検証した時には気がついていたけど伝えてなかった。開発側がebextensions書いてTable作るとのことでそのままお任せしてしまった。
高速Backend開発。忙しすぎる開発者。
そしてリリースされるアプリ。
オートスケールしないクソ弱いDB。
当然詰まる。
死。

はい。雑にまとめておきましょう。

教訓

  • なんとなく嫌な予感は大切にしましょう
  • 気になることはなんでも伝えましょう
  • 忙しい人は細かいこと忘れるので、少しでも余裕がある人が地雷を気にしてあげましょう
  • 後で絶対にやる・確認するタスクは分かりやすいところに置きましょう。今回はリリース前に気になりリストを最終確認する時間を取れば問題起こらなかったですね。github issueとかだとめっちゃ急いでいると見るの忘れるので、slackのリマインダ機能使いましょう。

最後の行がこの話で書きたかったこと。忘れそうなものは分かりやすいところへ。PULL型ではなくてPUSHで教えてくれるように。

以上

はじめてnodejsを使った。はじめてbotを作った話。

これは何

nodejsを使ってslack botを作った話。 インフラエンジニアだけどコードもかけるようになりたい、といって少しだけ時間をもらってbotを作る仕事をやった。 その時のメモ的なもの。

何を使う

botkitというツールキットを使う。 hubotと何が違うの? そういうのを調べたりはしてません。お手軽にモダンな感じで作れるよ、とおすすめされたので使った見た感じ。

コード

コードは長くないのでここに貼ってしまう。
npm install --save botkit とかして、package.json作らせた(と思う)。
channel id はチャンネルがprivateの場合はhttps://api.slack.com/methods/groups.list/test で確認する。publicの場合は /channels.list/test で確認する。slackの場合。facebook messanger とかだとまた別の取得方法だと思う。
token はbot のものを使用する。https://dwango.slack.com/apps/new/bot から作成したもの。custom botについてはこちらを参照のこと:https://api.slack.com/bot-users

const Botkit = require('botkit');
const os = require('os');

// 色々変数チェック。他dest,originについてはここの説明では略
if (!process.env.token) {
  console.warn('Error: Specify token in environment');
  process.exit(1);
}

const controller = Botkit.slackbot({
  debug: true,
});

controller.spawn({
  token: process.env.token,
}).startRTM();

const destChannel = process.env.destChannel;
const originChannel = process.env.originChannel;

controller.hears('.*https?://www.example.com[sS]*', 'ambient', (bot, message) => {  // [sS]* は改行含む全一致。.*だと改行入らない。ambient はbotが全発言を拾うということ(direct_messageとかもある)。 
  // 指定のチャンネルのときのみ発言を拾う
  if (message.channel === originChannel) {
    const matchMessage = message.text;
    const userId = message.user;
    bot.api.users.info({ user: userId }, (userApiError, userApiRes) => {
      const userName = userApiRes.user.profile.real_name;
      bot.api.channels.info({ channel: message.channel }, (channelApiError, channelApiRes) => {
        // private channel はchannels apiからは情報取得できない。groups apiなら取れるが、privateチャンネル名は知られなくても良い
        const channelName = (channelApiError !== 'channel_not_found') ? channelApiRes.channel.name : 'どこかprivate channel';
        bot.say(
          {
            text: `${userName}さんが作品リンクを投稿しました(in #${channelName}) \n -------------------------- \n ${matchMessage} \n --------------------------`,
            channel: destChannel,
          });
      });
    });
  }
});

起動は

originChannel='<channel_id1>' destChannel='<channel_id2>' token=<bot_token> node urlcopy_bot.js

その他

eslint 使ってみた。 明らかな表記ブレは適当に直してくれるし、コードはきれいになるし、紛らわしい表記とか教えてくれるし、割と良かった。 他のところにもlint入れてみようかなと思った。

追記

slack接続が切れてしまって(close RTMになる) botが死んだように見える現象があった。 最初は自分で close_rtmイベントをフックしてconnectするように書いていたが、botkitはデフォルトで予期せぬ接続断があったらreconnectするようになっているため、両方で接続しに行ってしまい、多重接続(このbotの場合は2回投稿してしまう動き)。参考:https://github.com/howdyai/botkit/blob/bee9c5c70dcf3c024e71f2a10bdb2e425c421988/lib/Slackbot_worker.js#L230-L233
また、その他のエラーでcloseRTMしたときにはretryEnabledがtrueならreconnectしてくれるっぽい。こちらの動作に任せることにした。参考: https://github.com/howdyai/botkit/blob/bee9c5c70dcf3c024e71f2a10bdb2e425c421988/lib/Slackbot_worker.js#L70-L86
そこで、ドキュメントの通り、

const controller = Botkit.slackbot({ retry: Infinity });

みたいにしたらちゃんと接続が切れてもreconnectしてくれるようになった。

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 というツールで取った。 ざっくりまとめておく。

github.com

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

実際にやったコマンドとは異なるが、サンプルとして書いておく。以下雑な説明

  • -p port
  • -P protocol
  • –threads クライアントのスレッド数
  • -c スレッド数あたりのコネクション数。トータル4*250=1000となる
  • –test-time テスト時間
  • –data-size-list. 今回はmemcachedからredisへの移行が目的。現行のmemcachedのデータに合うようにweightを決めた(別記事として書くかもしれない)
  • –key-prefix key長を適当に調整するために使える
  • –key-maximum キーのバリエーションになると思う