hayashier Tech Blogs
  • hayashier Tech Blogs
  • Author's Books
    • 実践Redis入門 (日本語版)
    • 実践Redis入門 (한국어판)
  • Top Contents
    • Dive Deep Redis
    • Dive Deep Memcached
    • Kubernetes 入門
    • TCP 入門
    • TLS 入門
    • GPG 入門
    • サービス障害が発生した場合の対応方法
    • よく使うトラブルシューティング コマンド実行例 まとめ
    • コピペで使えるELBのアクセスログ解析による事象分析 (ShellScript, Athena)
  • Containers
    • Docker 入門
    • Nomad 導入
    • Dockerを利用してさっと検証環境構築
  • Kubernetes
    • Kubernetes 入門
    • Kubernetes 導入 with Amazon Linux 2
    • EKSを利用してKubernetesでSpring MVCをデプロイ (NLB + Auto Scaling)
  • Load Balancer
    • ALB 認証 導入
    • TLS extensions support with ALB
    • ELB(CLB,ALB,NLB)の種類ごとのHTTPレスポンスの違い
    • ELB(CLB) で WebSocket 通信
  • RDBMS
    • PostgreSQL DBA 入門
    • RDBMS Benchmark Get Started
    • RDBMS サンプルデータ生成 Get Started
    • RDS PostgreSQL Extensions Get Started
    • RDBMS Engine Inspection for Troubleshooting
  • Redis
    • Dive Deep Redis ~ 入門から実装の確認まで
    • Dive Deep Redis Internals ~ GETコマンド実行時の動作 ~
    • RedisのString型は今でも本当に512MBが上限か?
    • Redis 公式ドキュメント まとめ
    • Redis / Memcached Source Code Reading - Overview -
  • Memcached
    • Dive Deep Memcached ~ 入門から実装の確認まで ~
    • Dive Deep Memcached ~ SETコマンド実行時の動作 ~
    • Memcached 公式ドキュメント まとめ
    • memtier_benchmark + memcached-tool の導入
    • Redis / Memcached Source Code Reading - Overview -
  • Hadoop
    • Hadoop Get Started
  • Networking
    • TCP 入門
    • TLS 入門
    • ksnctf: HTTPS is secure, Writeup (TLS 通信解読)
    • オンプレ側ルーター(Cisco 1812J, Juniper SRX210, YAMAHA RTX 1210)から Direct Connect へ BGP 設定
  • Software
    • アルゴリズムとデータ構造 入門
    • デザインパターン 入門
    • ソフトウェアテスト 入門
  • System Admin
    • Shell Script 入門
    • サービス障害が発生した場合の対応方法
    • よく使うトラブルシューティング コマンド実行例 まとめ
    • コピペで使えるELBのアクセスログ解析による事象分析 (ShellScript, Athena)
    • GPG 入門
    • Operation Misc
  • Development
    • ローカル環境のプログラミング言語のバージョンを切り替え macOS
    • /usr/local/Cellar/pyenv/1.2.21/libexec/pyenv: No such file or directoryのエラーの対処方法
  • AWS
    • AWS Misc
    • AWS CLI, AWS SDKのリトライ処理の実装について
    • AWS CLI バージョンアップでエラー発生を解消
    • Elastic Beanstalkで稼働しているアプリケーション(Ruby, Sinatra)をAmazon Linux AMIからAmazon Linux2へ移行
    • Elastic Beanstalkでインスタンス入れ替え後にnginxのデフォルトの画面が表示されてしまう問題の対応
    • Amazon Lightsail に SSL 証明書設置 with Let's Encrypt (自動更新)
    • Amazon Lightsailで10分で作るお手軽Markdownで書く独自ドメインのブログサイト構築
    • Lambdaをローカルでテスト(with Docker)
    • ECS + ALB でダウンタイムなしでデプロイ
    • `Repository packages-microsoft-com-prod is listed more than once in the configuration`のメッセージの解消方法
  • Others
    • Pandoc 導入
    • textlint + prh による文章校正
    • 紙書籍をPDFに変換
    • Sphinx 導入
    • さくっとPocketのブックマークをはてなブックマークに移行
    • Macが突然起動しなくなった話
    • Macでターミナルが開かない (zsh編)
    • ホスト型 IDS Tripwire とネットワーク型 IDS Snort の導入 with CentOS 6
    • JMeter 導入
    • Squid 導入 with Amazon Linux AMI
    • Spring MVCを導入 (+ MySQL, Redis)
    • 外資系企業で働いている場合の確定申告方法 (RSU考慮)
Powered by GitBook
On this page
  1. Redis

RedisのString型は今でも本当に512MBが上限か?

PreviousDive Deep Redis Internals ~ GETコマンド実行時の動作 ~NextRedis 公式ドキュメント まとめ

Last updated 1 month ago

RedisのString型は今でも本当に512MBが上限か?

RedisのString型が512MBが上限であると言われる事が多いことをご存知の方も多いかもしれません。 実際に、Redisの公式ドキュメント()にも以下のように記載されています。

  • キーの制限

The maximum allowed key size is 512 MB.

  • 値の制限

A value can’t be bigger than 512 MB.

この512MB制限は、キーと値のそれぞれ両方に適用される制限です。理由はRedisの文字列はで管理されており、バージョン1の制限によります。バージョン2でその制限がなくなりましたが、512MBの制限撤廃のためにはRedis側でも追随する必要がありました。

一方で、String型の512MBのIssueがクローズされていることを確認しました。すなわち、今現在は512MBの制限がなくなったようです。Redis 4.0.7でproto-max-bulk-lenディレクティブが追加されているので、このタイミングと考えられます。

関連するディレクティブ(パラメーター)として2種類あり、proto-max-bulk-lenは実際に実行するコマンドのバイト数の制限、client-query-buffer-limitはRESPのフォーマットを含めたバイト数で制限されます。これらを調整しながら確認していきます。

では、実際に検証して10GBのようなデータでも値として送ることができるのか確認してみましょう。今回はredis-pyを使用して確認します。インストールしていない場合は、pip3 install redisなどで事前にインストールしておいてください。

検証は、MacOSおよびAWSのEC2インスタンスでUbuntu, 20.04 LTS(オレゴンリージョンのAMI ami-03d5c68bab01f3496)、インスタンスタイプはr5.24xlargeのものを使用しました。

最初はMacOS上で検証します。最初からEC2上で検証しても問題ありません。

string512.pyという名前で以下のように512MiBの値をString型として保存する検証用コードを準備します。

import redis

client = redis.Redis(host = '127.0.0.1', port = 6379)
client.set('str512', "a" * int(512 * 1024 * 1024))

print(client.strlen('str512'))

以下のように実行します。

$ python string512.py
536870912

512MBより大きい値を送ると以下のエラーが返ってきます。

$ python string512.py
Traceback (most recent call last):
  File "/Users/hayashier/.pyenv/versions/3.9.0/lib/python3.9/site-packages/redis/connection.py", line 706, in send_packed_command
    sendall(self._sock, item)
  File "/Users/hayashier/.pyenv/versions/3.9.0/lib/python3.9/site-packages/redis/_compat.py", line 9, in sendall
    return sock.sendall(*args, **kwargs)
OSError: [Errno 41] Protocol wrong type for socket

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/hayashier/string512.py", line 4, in <module>
    client.set('str512', "a" * (512 * 1024 * 1024 + 1))
  File "/Users/hayashier/.pyenv/versions/3.9.0/lib/python3.9/site-packages/redis/client.py", line 1801, in set
    return self.execute_command('SET', *pieces)
  File "/Users/hayashier/.pyenv/versions/3.9.0/lib/python3.9/site-packages/redis/client.py", line 900, in execute_command
    conn.send_command(*args)
  File "/Users/hayashier/.pyenv/versions/3.9.0/lib/python3.9/site-packages/redis/connection.py", line 725, in send_command
    self.send_packed_command(self.pack_command(*args),
  File "/Users/hayashier/.pyenv/versions/3.9.0/lib/python3.9/site-packages/redis/connection.py", line 717, in send_packed_command
    raise ConnectionError("Error %s while writing to socket. %s." %
redis.exceptions.ConnectionError: Error 41 while writing to socket. Protocol wrong type for socket.

そこで、proto-max-bulk-lenディレクティブの値を512mbから10gbに変更します。すると、512MiB+1Bのデータも送信できるようになります。

$ python string512.py
536870913

今度は1GB以上の値を送ると以下のエラーが返ってきます。

$ python string512.py
Traceback (most recent call last):
  File "/Users/hayashier/string512.py", line 4, in <module>
    client.set('str512', "a" * (1 * 1024 * 1024 * 1024))
  File "/Users/hayashier/.pyenv/versions/3.9.0/lib/python3.9/site-packages/redis/client.py", line 1801, in set
    return self.execute_command('SET', *pieces)
  File "/Users/hayashier/.pyenv/versions/3.9.0/lib/python3.9/site-packages/redis/client.py", line 901, in execute_command
    return self.parse_response(conn, command_name, **options)
  File "/Users/hayashier/.pyenv/versions/3.9.0/lib/python3.9/site-packages/redis/client.py", line 915, in parse_response
    response = connection.read_response()
  File "/Users/hayashier/.pyenv/versions/3.9.0/lib/python3.9/site-packages/redis/connection.py", line 739, in read_response
    response = self._parser.read_response()
  File "/Users/hayashier/.pyenv/versions/3.9.0/lib/python3.9/site-packages/redis/connection.py", line 324, in read_response
    raw = self._buffer.readline()
  File "/Users/hayashier/.pyenv/versions/3.9.0/lib/python3.9/site-packages/redis/connection.py", line 256, in readline
    self._read_from_socket()
  File "/Users/hayashier/.pyenv/versions/3.9.0/lib/python3.9/site-packages/redis/connection.py", line 201, in _read_from_socket
    raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
redis.exceptions.ConnectionError: Connection closed by server.

Redisサーバー側には以下のメッセージが表示されます。

43159:M 20 Sep 2021 14:03:27.540 # Closing client that reached max query buffer length: id=7 addr=127.0.0.1:55539 laddr=127.0.0.1:6379 fd=9 name= age=1 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=1073741826 qbuf-free=835572 argv-mem=9 obl=0 oll=0 omem=0 tot-mem=1074594857 events=r cmd=NULL user=default redir=-1 (qbuf initial bytes: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")

そこでclient-query-buffer-limitディレクティブの値を1gbから11gbに変更します。前述の通り、client-query-buffer-limitはRESPのフォーマットを含めたバイト数で制限されますので、少し多めに確保しています。

1GBでもデータを送ることができるようになりました。

$ python string512.py
1073741824

ここからは検証サイズが大きくなってきましたので、ローカル端末ではなく、大きめのEC2インスタンスを立てて検証します。

次に、4GBより大きな値を送ると以下のようにエラーが返ってきました。

$ python3 string512.py 
Killed

freeコマンドを定期的に取ると、メモリーを使い切ってそうです。

$ free -m
              total        used        free      shared  buff/cache   available
Mem:          15823       14257        1430           0         134        1327
Swap:             0           0           0
$ free -m
              total        used        free      shared  buff/cache   available
Mem:          15823       14799         889           0         134         785
Swap:             0           0           0
$ free -m
              total        used        free      shared  buff/cache   available
Mem:          15823       15323         364           0         134         261
Swap:             0           0           0
$ free -m
              total        used        free      shared  buff/cache   available
Mem:          15823       11105        4662           0          55        4519
Swap:             0           0           0
$ free -m
              total        used        free      shared  buff/cache   available
Mem:          15823        8157        7609           0          55        7466
Swap:             0           0           0

そこでr5.24xlargeに変更に変更したところ(その前はr5.12xlargeで検証していました)、無事10GiBのデータも送ることができるようになりました。

$ python3 string512.py 
10737418240

値だけではなく、キーの512MB制限について試す場合も同様に検証できます。コードを以下のように修正するのみです。

import redis

client = redis.Redis(host = '127.0.0.1', port = 6379)
client.set("a" * int(10 * 1024 * 1024 * 1024), 'value512')
print(client.strlen("a" * int(10 * 1024 * 1024 * 1024)))  

ドキュメントにも修正依頼を出しておきました。

An introduction to Redis data types and abstractions
SDS(Simple Dynamic Strings)
Remove 512 MB max value limit · Issue #757 · redis/redis
Remove the description about String 512MB limit by hayashier · Pull Request #1653 · redis/redis-doc