记Redis那坑人的HGETALL
世上本没有坑,摔的人多了,也便成了坑。 早就听人说过Redis的HGETALL是个坑,可我偏偏不信邪:不管什么坑,一定要自己踩上去跺两脚才肯罢休。说好听点这是不到黄河心不死,说难听点就是不见棺材不落泪。 开始程序运行的非常稳定,稳定到我想送所有说HGETALL
世上本没有坑,摔的人多了,也便成了坑。
早就听人说过Redis的HGETALL是个坑,可我偏偏不信邪:不管什么坑,一定要自己踩上去跺两脚才肯罢休。说好听点这是不到黄河心不死,说难听点就是不见棺材不落泪。
开始程序运行的非常稳定,稳定到我想送所有说HGETALL是个坑的人一个字:呸!此时的我就像温水里的青蛙一样忘记了危险的存在,时间就这样一天一天的过去,突然有一天需求变了,我不得不把HASH数据的内容从十几个字段扩展到一百多个字段,同时使用了Pipelining一次性获取上百个HGETALL的结果。于是我掉坑里了:服务器宕机。
为什么会这样?Redis是单线程的!当它处理一个请求时其他的请求只能等着。通常请求都会很快处理完,但是当我们使用HGETALL的时候,必须遍历每个字段来获取数据,这期间消耗的CPU资源和字段数成正比,如果还用了PIPELINING,无疑更是雪上加霜。
如何解决这个问题?请容许我煞有其事的给出一个公式:
PERFORMANCE = CPUs / OPERATIONs
也就是说,此场景下为了提升性能,要么增加运算过程中的CPU数量;要么降低运算过程中的操作数量。具体来说,我大致想到了以下几种方法:
借助Memcached
Redis存储方式不做任何改变,额外的,我们借助Memcached实现一套缓存,里面存储原本需要在Redis里HGETALL的HASH,当然,由于Memcached里存储的都是字符串,所以当我们存储HASH的时候,实际上存储的是HASH序列化后的字符串,查询的时候再反序列化即可,通常Memcached客户端驱动可以透明实现序列化和反序列化的过程。此方案的优势在于因为Memcached支持多线程,所以可以让更多的CPU参与运算,同时由于不用再遍历每一个字段,所以相应的操作会减少;当然劣势也不少,因为引入了一个新的缓存层,所以浪费了内存,增加了复杂性,另外,有时候即便我们只需要获取少数几个字段的数据,也不得不先查询完整的数据,然后再筛选,这无疑浪费了带宽。当然这种情况下我们可以直接查询Redis,但是无疑又提升了一些复杂性。
顺便说一句,Memcached支持Multiget,可以实现类似Pipelining的效果,但你要格外小心这里面有关Memcached的坑,也就是Mulitiget无底洞问题。
序列化字段冗余
Redis在存储HASH的时候,多保存一个名为「all」的字段,其内容是原HASH数据的序列化,实际查询的时候,只要HGET这个冗余字段后再反序列化即可。此方案的优势在于通过序列化字段冗余,我们把原本的HGETALL操作简化为HGET,也就是说,不再需要遍历HASH中的每一个字段,因此即便不能让多个CPU参与运算,但是却大幅降低了操作数量,所以性能的提升仍然是显著的;当然劣势也很明显,和所有的冗余方式一样,此方案浪费了大量的内存。
有人会问,这样虽然没有了遍历字段的过程,但是却增加了反序列化的过程,而反序列化的成本往往也是很高的,难道这样也能提升性能?问题的关键在于开始我们遍历字段的操作是在一个CPU上完成的,后来反序列化的操作,不管是什么语言,都可以通过多进程或多线程来保证是在多个CPU上完成的,所以性能总体上是提升的。
…
另外,很多人直觉是通过运行Redis多实例来解决问题。确实,这样可以增加运算过程中的CPU数量,有助于提升性能,但是需要注意的是,HGETALL和PIPELINING往往会让运算过程中的操作数量呈几何级爆炸式增长,相比之下,我们能增加的Redis多实例数量简直就是杯水车薪,所以本例中这种方法不能彻底解决问题。
…
坑,就是用来踩的。不用怕掉进去,当然前提是你能自己爬出来!
原文地址:记Redis那坑人的HGETALL, 感谢原作者分享。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











Redisクラスターモードは、シャードを介してRedisインスタンスを複数のサーバーに展開し、スケーラビリティと可用性を向上させます。構造の手順は次のとおりです。異なるポートで奇妙なRedisインスタンスを作成します。 3つのセンチネルインスタンスを作成し、Redisインスタンスを監視し、フェールオーバーを監視します。 Sentinel構成ファイルを構成し、Redisインスタンス情報とフェールオーバー設定の監視を追加します。 Redisインスタンス構成ファイルを構成し、クラスターモードを有効にし、クラスター情報ファイルパスを指定します。各Redisインスタンスの情報を含むnodes.confファイルを作成します。クラスターを起動し、CREATEコマンドを実行してクラスターを作成し、レプリカの数を指定します。クラスターにログインしてクラスター情報コマンドを実行して、クラスターステータスを確認します。作る

Redisデータをクリアする方法:Flushallコマンドを使用して、すべての重要な値をクリアします。 FlushDBコマンドを使用して、現在選択されているデータベースのキー値をクリアします。 [選択]を使用してデータベースを切り替え、FlushDBを使用して複数のデータベースをクリアします。 DELコマンドを使用して、特定のキーを削除します。 Redis-CLIツールを使用してデータをクリアします。

Redisのキューを読むには、キュー名を取得し、LPOPコマンドを使用して要素を読み、空のキューを処理する必要があります。特定の手順は次のとおりです。キュー名を取得します:「キュー:キュー」などの「キュー:」のプレフィックスで名前を付けます。 LPOPコマンドを使用します。キューのヘッドから要素を排出し、LPOP Queue:My-Queueなどの値を返します。空のキューの処理:キューが空の場合、LPOPはnilを返し、要素を読む前にキューが存在するかどうかを確認できます。

Redis指令を使用するには、次の手順が必要です。Redisクライアントを開きます。コマンド(動詞キー値)を入力します。必要なパラメーターを提供します(指示ごとに異なります)。 Enterを押してコマンドを実行します。 Redisは、操作の結果を示す応答を返します(通常はOKまたは-ERR)。

Redisを使用して操作をロックするには、setnxコマンドを介してロックを取得し、有効期限を設定するために有効期限コマンドを使用する必要があります。特定の手順は次のとおりです。(1)SETNXコマンドを使用して、キー価値ペアを設定しようとします。 (2)expireコマンドを使用して、ロックの有効期限を設定します。 (3)Delコマンドを使用して、ロックが不要になったときにロックを削除します。

Centosシステムでは、Redis構成ファイルを変更するか、Redisコマンドを使用して悪意のあるスクリプトがあまりにも多くのリソースを消費しないようにすることにより、LUAスクリプトの実行時間を制限できます。方法1:Redis構成ファイルを変更し、Redis構成ファイルを見つけます:Redis構成ファイルは通常/etc/redis/redis.confにあります。構成ファイルの編集:テキストエディター(VIやNANOなど)を使用して構成ファイルを開きます:sudovi/etc/redis/redis.conf luaスクリプト実行時間制限を設定します。

Redisコマンドラインツール(Redis-Cli)を使用して、次の手順を使用してRedisを管理および操作します。サーバーに接続し、アドレスとポートを指定します。コマンド名とパラメーターを使用して、コマンドをサーバーに送信します。ヘルプコマンドを使用して、特定のコマンドのヘルプ情報を表示します。 QUITコマンドを使用して、コマンドラインツールを終了します。

Redisデータの有効期間戦略には2つのタイプがあります。周期削除:期限切れのキーを削除する定期的なスキャン。これは、期限切れの時間帯-remove-countおよび期限切れの時間帯-remove-delayパラメーターを介して設定できます。怠zyな削除:キーが読み取られたり書かれたりした場合にのみ、削除の有効期限が切れたキーを確認してください。それらは、レイジーフリーレイジーエビクション、レイジーフリーレイジーエクスピア、レイジーフリーラジーユーザーのパラメーターを介して設定できます。
