tech.guitarrapc.cóm

Technical updates

EC2など 高負荷クラウド環境における Redis のチューニングについて

たまにはPowerShell 以外の記事を。

某記事でもRedis (REmote DIctionary Server)が memcached に代わり得る利点がBookSleeveを交えて丁寧に説明されました。

そして、Redisの運用が一定の目途を見せていることから、その初期設定に欠かせないチューニングについて記事にしてみようと思います。 全部明かすわけではありませんが、なかなかRedisに関する記事は少ないので、少し参考になれば幸いです。

経験上、高負荷環境ではRedisはチューニングで大幅に安定性が変わります。 インストール? 沢山記事ありますし、簡単なのでここでは省きます。 どうしても!な場合は希望していただければ記事にしますが。

Redis Quick Start

 

対象バージョン

2.6系とします。 2.4系でも大方一緒ですが、2.6系に特有な部分があるので、注意です。

対象OS

Redis は Linux ベースでの運用を主眼に置かれています。 Win32/64は直接サポートではありませんのでご注意を。一応、Microsoft Open Tech group が実験版の開発とメンテを行っているようですが。

Download

今回のチューニングは Linux、特にAWS EC2インスタンスです。

負荷と環境

ざっくりと注意点を並べておきます。

Call

20000 call /sec ~ が常時かかっている状況に平然と耐えれる程度ということで。 当然ベンチでは 40000 call /sec 超えますが平均しておきましょう。

Connection

5000 conn/every も耐えますが、その辺は実際のRedis 負荷になるのが call なので一定の目安にしかなりません。

CPU

CPU に関しては、 RedisはSingle Threadで動作することもあり、動作中はそれほど CPUを喰いません。 とはいえ結構カツカツまで利用すると 1 core 80%とかも目指せます。

このあたりは、繰り返しますが、Call に依存する部分が大きいのは当然といえば当然ですが、BookSleeveを活用した PipeLining は当然必須です。

High System CPU Usage Redis latency problems troubleshooting

AOF での Disk I/O、 RDB のDir 指定ミス、 RDB での bgsaveに伴う BackGround Threadへのrdb処理時 などにCPUが膨らみますが、その辺は日本語では記事がないですね。 もったいないです。 (でもここでは書きません(( )

Persistence

Persistence = 永続化ですが、今回は Apend Only File ではなく RDB を採用した場合とします。 RDB と AOF に関しては、 Persistence の程度は勿論の事、Letency にも大きくかかわるため、良く考慮してください。

Redis Persistence Redis latency problems troubleshooting

Virtual Environment

Virtual Memory ではありません、 仮想環境です。 Virtual Memory は、サルバトーレ御大も失敗と認め 2.4で廃止と明言していますので、くれぐれも使われないように (

Virtual Memory

Redisですが、 仮想環境 (Amazon EC2もそうですね) 、で 物理環境の同一性能 マシンに比較して性能を落とすことが公式に認められています。

Redis latency problems troubleshooting
Fork time in different systems Modern hardware is pretty fast to copy the page table, but Xen is not. The problem with Xen is not virtualization-specific, but Xen-specific. For instance using VMware or Virutal Box does not result into slow fork time. The following is a table that compares fork time for different Redis instance size. Data is obtained performing a BGSAVE and looking at the latest_fork_usec filed in the INFO command output.
  • Linux beefy VM on VMware 6.0GB RSS forked in 77 milliseconds (12.8 milliseconds per GB).
  • Linux running on physical machine (Unknown HW) 6.1GB RSS forked in 80 milliseconds (13.1 milliseconds per GB)
  • Linux running on physical machine (Xeon @ 2.27Ghz) 6.9GB RSS forked into 62 millisecodns (9 milliseconds per GB).
  • Linux VM on 6sync (KVM) 360 MB RSS forked in 8.2 milliseconds (23.3 millisecond per GB).
  • Linux VM on EC2 (Xen) 6.1GB RSS forked in 1460 milliseconds (239.3 milliseconds per GB).
  • Linux VM on Linode (Xen) 0.9GBRSS forked into 382 millisecodns (424 milliseconds per GB).

Redisの構築

某謎社の場合、インストールとベース設定は【EC2のSnapshot運用】 、個別のチューニングが 【capistranoを利用したチューニング適用】でほぼ自動化しています。

例えn台あったとしても、 実行時と実行後の設定周り確認も含めて、新規インスタンスを起動から運用にいれるまでは 30分 もあれば終わります。 (大半が EC2のSnapshot起動なのですが)

それだけ Redisは 安定しており、チューニングも一定の効果をキッチリ出せる極めて優れた品質と言えると思います。

PV か HVM インスタンスの選択

Amazon Linux といえば、Xen ですね。2013年までは PVが主流でしたが、2014年以降は HVMが主流です。

HVMでないと、r3インスタンスも使えず、またネットワーク周りの高速化、CPUの IvyBridge系利用もできずシングルスレッド処理も伸びません。

間違いなく HVMインスタンスを使わない理由はないので、ぜひ PVは捨ててください。

Linux Tuning

ようやく主題となるチューニングです。 まず Linux Tuningから見てみましょう。

IPv6周り

当然というかなんというか、 IPv6 を使わず IPv4 でそろえた方が安定性が高いのは事実です。 残念ですしこれが最善ともおもいませんが、 LAN内部においてはまだまだ IPv4 が安定して利用できるのは事実です。

resolv.conf

IPv4なら当然この要素は外せません。 EC2の場合は、実は少しトリックが要りますが省きます。

options single-request-reopen

他のIPv6関連もげもげは、まぁ大丈夫ですよね。

ただ、2014年9月以降のHVM インスタンスでは resolve.conf をいじらずとも v4通信のみがredisで動いているので余り気にしなくても大丈夫です。

sysctl周り

負荷具合にもよりますが、この辺は大事です。

/etc/sysctl.conf

に記述することで、再起動後も適用されています。 嫌なら sysctlとか/proc書き換えでどうぞ。

port_range

linux のデフォルトポートレンジでは足りないほどの高負荷環境。 それならば設定は必要ですね。 最大域にするならこうです。 むしろそこまで高負荷環境ではこの程度は焼け石に水ですが、まぁ後述の設定が出来るなら此処はあまり問題になりません。

net.ipv4.ip_local_port_range = 1024 65000

somaxconn

memcached でもbacklog と並んで重要なパラメータですが、Redisでも当然重要です。 状況によるかと思いますが、例えば1024にするなら以下です。

net.core.somaxconn = 1024

tcp_fin_timeoutと tcp_tw_recycle

tcp_tw_recycleですが、 NAT環境でパケットのtimeoutがほげほげでsyn_packetがという問題を良く理解した上で設定を施すか考慮、検証しなくてはいけません。

繰り返しますが、気安くやるとネットワークが意図せず不通/パケットロストになるなど「痛い目にあう可能性がある」ので気を付けてください。

また、tcp_fin_timeout設定は tcp_tw_recycleを有効にした上でないとデフォルト値の60secから変わりませんのでご注意ください。(あるいは linux sourceで cいじってbuildでもいいですけど)

※ もしこの設定が適用できる場合、 port_rangeに関しては不要になる可能性が高いです。 例えば、tcp_fin_timeout を 30秒にするなら以下です。

net.ipv4.tcp_fin_timeout = 30

例えば、tcp_tw_recycle を 有効にするなら以下です。

net.ipv4.tcp_tw_recycle = 1

FileDescriptor周り

Redisに限らず ネットワークのやり取りが多い場合は当然必要です。 limits.conf や pam.dのチューニングは必ず行いましょう。

その他 Kernel チューニング

最も大きく関わる足回りを中心に紹介しました。 その他は環境に応じて、各自の設定があるかと思います。

Redis Config

デフォルトでは、 /etc/redis/redis.conf です。 redis.conf のチューニングに関しては、それほど複雑でもありません。 また、AOFではなく RDBのパターンなので、 latencyにも気を使う必要が小さく簡単です。

daemonize

daemon化すると redis のログは出力されません。 ご自由にどうぞ。

daemonize yes

pidfile

敢えて理由がない限りは変更の必要はないですね。 ご自由にどうぞ。

pidfile /var/run/redis.pid

port

デフォルトは TCP 6379です。 iptableにSELinux など各自の事情に応じてどうぞ。

port 6379

bind

バインドするnetworkインターフェースです。 特に理由がなければremarkしても問題ありません。 ご自由にどうぞ。

# bind 127.0.0.1

unixsocket

unix domain socket 利用する場合です。 Appと同一サーバーにするなどでしか使いませんが、さて。 TCP/IPを利用するなら リマークです。 ご自由にどうぞ。

# unixsocket /tmp/redis.sock
# unixsocketperm 755

timeout

クライアントから n 秒間の通信がない場合のタイムアウトです。 0でtimeout無しです。 port使用状況 や connectionの張り方に応じてどうぞ。

timeout 600

TCP keepalive

もし 0出ない場合、クライアントとの無通信時に TCP ACKs を送るのに SO_KEEPALIVE を利用します。 ダメになった peerの検出や、ネットワーク維持の明示に役立ちます。 推奨値は 60 (秒)です。

tcp-keepalive 60

loglevel

logの程度です。 出力はdaemon次第ですので悪しからず。 debug、verbose、notice、warningとありますが、本番では noticeが推奨です。

loglevel notice

logfile

logfileの出力先です。 daemonにしてると 設定値がどうあれ、/dev/null に破棄されますのでご注意を。

logfile /var/log/redis/redis.log

syslog-enabled

syslogを有効にするかです。 お好きにどうぞ。 勿論リマークも可です。

# syslog-enabled no

syslog-facility

syslogを実行する際のアレです。 USERか、LOCAL0-LOCAL7である必要あります。

# syslog-facility local0

database

利用するdatabaseの数です。 デフォルトは DB 0を利用し、0 ~ databses-1 まで利用可能です。

databases 16

Snapshot

RDBに関することだけにしますね。

save

RDBを取る頻度です。 save n x とは、n秒にx 回の変更に付き bgsave を行うという考えです。 saveしない (In-Memoryとしての利用) 場合、 save "" となります。

save 900 1
save 300 10
save 60 100000

stop-writes-on-bgsave-error

Redis は、 RDBが有効 & 前回の bgsave が失敗した場合、書き込みを受け付けなくなります。 こうすることで、 redis-infoなどでpersistence が失われている異常事態が分かるようにしています。

通常は無効にしないと思いますが、モニタの都合なので Disk 異常でも働かせたい場合に無効にします。

stop-writes-on-bgsave-error yes

rdbcompression

RDBは メモリのダンプですが、保存するときに 圧縮するかどうかです。 圧縮すると CPUは喰うものの、容量が大幅に圧縮できます。

rdbcompression yes

rdbchecksum

CRC64でのRDBのchecksum検査をお熟します。 破損の検知は永続性で最重要なので、行わない理由はないかと。 ただし、RDBのsaveとloadで10%のパフォーマンス低下が起こります。

rdbchecksum yes

dbfilename

RDBファイル名です。

dbfilename dump.rdb

dir

RDBを保存する、パスです。 先のdbfilename とセットになって、保存フルパスが定まります。

このパスを間違えると、 RDBのbgsaveに失敗し、Redis のCPU が常に高い状況が起こりえます。 Redis で CPUが常に100%なのはまずありません。異常事態なので必ず存在するパスである事、権限などRDBが生成できている事などを確認しましょう。

dir /var/lib/redis/

REPLICATION

Slaveは今回省きます。

SECURITY

Securityは今回省きます。

LIMITS

2.6.12あたりで FileDescriptor周りが変わりました。

maxclients

最大接続クライアントです。 デフォルトでは 10000となります。 ここは file descriptor に上限が左右されます。(File Descriptor -32) 上限に達すると、'max number of clients reached' とエラーを返します。 無効にする場合は、 #maxclients とリマークします。

maxclients 10000

maxmemory

Redisが利用する最大メモリ(bytes)です。 そのままですね。 無効にするとシステムの最大まで利用を試みます。 無効にする場合は、 # maxmemory とリマークします。

# maxmemory <bytes>

MAXMEMORY POLICY

基本的には変更に必要がないです。 maxmemoryに到達した時にredisがどのようにmemory を開放するかの処理です。

# maxmemory-policy volatile-lru

APPEND ONLY MODE

AOFは今回省きます。 基本的には無効にするように設定しておきます。

appendonly no
appendfsync no
no-appendfsync-on-rewrite no

LUA SCRIPTING

LUA SCRIPTINGを利用する場合に使用します。 最大実行時間の設定のみで、デフォルトでも十分実用値です。

lua-time-limit 5000

SLOW LOG

処理に時間がかかったのモノを SLOW LOGに残す際の閾値です。 latencyの計測には欠かせません。

slowlog-log-slower-than 10000
slowlog-max-len 128

ADVANCED CONFIG

基本的には初期値のままでとサルバトーレ御大も行っていますが、まぁしたい人はどうぞ。 ここでは省きます。

まとめ

いかがでしたでしょうか。

Linux / Redis 両面での推奨設定値を挙げるという事はしませんでしたが、日本語での説明も含めて目安となれば幸いです。

 

Redisはチューニングされていない linux & Redis でもある程度快適に動きます。 が、本気でチューニングした時との安定性は格段に上昇し、速度もキッチリ出ます。

EC2 の 同一 VPC / 同一 Zone 内部であれば ほぼ 遅延はなく、実質 network latency のみとなる (つまり 0.0x ms の処理) が実現できます。

是非、memcached などから Redis にメリットを感じる (C# なら特に!) 状況の場合は、採用されるといいかと思います。