blog

Redisメモリの最適化

集約されたデータ型Hash、List、Set、Sorted SetがすべてIntegerで構成されている場合、またはそのサイズが一定値以下の場合、Redisはそれらを非常にメモリ効率の良い方法でエンコ...

Apr 10, 2020 · 4 min. read
シェア
"

Redisのメモリ最適化のヒント、公式ドキュメントの翻訳+個人的な理解です!

"

集約されたデータ型であるHash、List、Set、Sorted SetがすべてIntegerで構成されている場合、またはSizeが特定の値以下の場合、Redisは非常にメモリ効率の高い方法でそれらをエンコードし、最大10倍のメモリを節約します。コーディングはCPUに負荷がかかるので、CPUとメモリの妥協点です。

hash-max-ziplist-entries 512
hash-max-ziplist-value 64
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
set-max-intset-entries 512

特殊エンコーディングのサイズが設定値を超えると、Redisは特殊エンコーディングを通常のエンコーディングに変換します。設定値が非常に大きい場合は、ベンチマークを使用してRedisがエンコーディングを変換するのにかかる時間をテストすることをお勧めします。

32ビットRedisの使用

Redisのソース・コードを32ビット・プログラムにコンパイルする場合、ポインタが小さいため、各キーが消費するメモリははるかに少なくなりますが、32ビットの最大アドレス空間はわずか4GBです。

Redisはシングルスレッドであるため、サーバーがマルチコアで大容量のメモリを搭載している場合は、1台のサーバーに複数のRedisノードを配置し、メモリとCPUの両方をフルに活用することを検討できます。

RDBとAOFは32ビットと64ビットを区別しないので、Redisは32ビットと64ビットを自由に切り替えることができます。

ビットおよびバイトレベルの操作

これらのコマンドを使用すると、Redisの文字列型をバイト/ビット配列のように操作できます。

例えば、1億人のユーザーを持つアプリでは、各ユーザーのIDは継続的に自己インクリメントされます。このとき、同じようなBitMap(ビットマップ)を使ってユーザーの性別を記録することができます。この方法でRedisに記録すると、1億人分のユーザー情報は12Mのメモリ容量で済みます。

もちろん、より多くの情報を記録する必要がある場合、0/1のビットでは満足できません。

複数のキー文字列のハッシュ型への置き換え

n個のkey-Stringはkey-Hash(n個のフィールドを持つハッシュ)よりも多くのメモリを消費します。

一方、key-Hashがある場合、Hash内の複数の属性は一緒に期限切れになるかどうかだけです。

キーハッシュがメモリを節約?

public class Student{
 private Long id;
 private Short age;
 private String name;
 private String email;
}

このような生徒オブジェクトがある場合、生徒オブジェクトの属性をハッシュテーブルに格納することで、複数の属性を格納するために複数のキー文字列を使用するよりも多くのメモリを節約できます。

キーハッシュの方が速い?

まず、前提条件として、時間の複雑さについてです。Nが非常に小さい場合、O(N)はO(1)にほぼ等しく、通常の状況では、key-Stringとkey-Hashの両方のルックアップ時間の複雑さはO(1)です。

Hashに十分な数のフィールドが含まれていない場合、RedisはそれをO(N)の時間複雑性を持つデータ構造としてエンコードします。時間の複雑さに関しては、Nは十分に小さいので影響はありません。しかし、キーと値のペアのこのような線形配列構造は、メインメモリよりもはるかに高速なCPUキャッシュによって十分にプリロードされ、ヒットすることができます。

ハッシュを使用する際のヒント

redisに入れられたキーが以下のような特徴を持っているとします:

object:
object:1234
object:5

例えば、object:201393はobject:2013と2つの部分に分割でき、最初の部分はキーハッシュのキーとして、後の部分はハッシュの属性として使用できます:

HSET object: somevalue

HSET文法補足: HSET KEY_NAME FIELD VALUE

プリ・スライシングと同様に、ハッシュごとに最大100個の要素を持つことができるという利点があります。

このアプローチに従うと、公式のメモリ最適化の結果、64ビットRedisでは11MBのデータが1.7MBに最適化されます。

なぜRedis全体をハッシュとして扱うのではなく、ハッシュの中で圧縮の最適化を行うのですか?理由は2つあります:

  • ハッシュだけを最適化すれば、CPUメモリ、圧縮、最大要素数の間で最適なトレードオフができます。また、Redis全体でトップレベルのキーが多すぎると、多くのCPUリソースを浪費することになります!
  • また、Redisのトップ・キーには、有効期限切れ、LRUなど、対処すべきことがたくさんあり、Redisのトップ・キーの操作全体が非常に複雑で非現実的であるという事実もあります!

メモリ割り当て

maxmemory は Redis の最大メモリを設定します。

以下はRedisのメモリ管理に関するメモです:

  • キーが削除されても、Redisはすぐにオペレーティング・システムにメモリ空間を返しません。これはRedisが特別だからではなく、メモリ領域の割り当て方法と関係があります。メモリ領域はページ数に応じてプロセスに割り当てられ、Redisから削除されたキーは有効なキーと同じページを占有する可能性があるため、このページがデータによって占有されている限り、オペレーティング・システムに返すことはできません。たとえば、Redisが5Gのデータを保存し、2Gを削除して3Gを残した場合、Redisプロセスは依然として5Gのメモリを占有しています。

  • 前者は、オペレーティング・システムが必要とするメモリを、ピーク時のメモリ使用量に基づいて計算する必要があることを意味します。

  • 2Gを削除して3Gが残っているときに5Gだった場合、2Gのデータを追加しても、Redisプロセスはキャッシュページの隙間を利用するため、5Gのメモリを消費します。

  • 断片化率は、Redisプロセスが占有するメモリ量をRedisに保存されているデータ量で割ることで求めることができ、ピークが非常に高い場合は断片化率も非常に高くなります

maxmemoryが設定されていない場合、Redisプロセスは、Redisが保存する必要のあるデータ量が非常に少量であっても、オペレーティング・システムのメモリ領域全体を占有する可能性があります。

Work in progress

進行中... 近日中にヒントを追加する予定です。

Read next

超強力な、プロジェクトの展開クリックボタンをすることができ、全体のプロセスの自動化!

通常、いくつかの小さなプロジェクトの開発では、公開する必要があるような急速な展開があり、私は最もインテリジェントな方法は、"公開 "を叫ぶことかもしれないと感じて、アプリケーションが自動的にパッケージ化され、サーバーに公開し、実行することができます。プロジェクトの規模が比較的小さいので、DevOpsチームには適用できないかもしれません。アプリケーションを素早く本番稼動させるための小さなツールが欲しいです。 Alibaba Cl...

Apr 10, 2020 · 3 min read