おっさんエンジニアの備忘録

とりあえず、忘れてもいいようにやってみたことを書いています。

StackExchange.Redisを使ってみる

今回の目的

Redisをプログラムから利用してみます。 今回はクライアントとして、C#のStackExchange.Redisを使ってみます。

StackExchange.Redisとは

StackExchange.Redis is a high performance general purpose redis client for .NET languages (C# etc). It is the logical successor to BookSleeve, and is the client developed-by (and used-by) Stack Exchange for busy sites like Stack Overflow. For the full reasons why this library was created (i.e. “What about BookSleeve?”) please see here.( StackExchange.Redis | General purpose redis client)

StackOverflowなどでも使われている高性能なRedisクライアント

Azure Redis CacheでもClientとして公開されいます。 https://docs.microsoft.com/ja-jp/azure/redis-cache/cache-dotnet-how-to-use-azure-redis-cache

サクッと追加参照してみる

StackExchange.Redisではコネクションをアプリの起動から終了まで使いまわす前提になっています。 そのため、通常のDBのようにusingなどは使わないようです。 とりあえず、コンソールアプリケーションでこんにちはと表示して何か入力するとさよならと表示するアプリケーションを作ってみました。 その時にリソースをRedisに保存しています。特に意味のあるアプリではないです。

using System;
using StackExchange.Redis;
using System.Threading;

namespace RedisSample
{
    class Program
    {
        static void Main(string[] args)
        {
            // クライアントアプリケーションの開始から終了するまで使いまわす。だからusingは不要。
            ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");

            // データベースを取得
            IDatabase cache = redis.GetDatabase();

            // 値を保存
            cache.StringSet("key:jp:hello", "こんにちは");
            cache.StringSet("key:jp:goodbye", "さようなら");

            // 保存した値を取得して利用する
            Console.WriteLine(cache.StringGet("key:jp:hello"));
            Console.ReadLine();
            Console.WriteLine(cache.StringGet("key:jp:goodbye"));
            Thread.Sleep(1000);
        }
    }
}

キーの命名は公式ドキュメントのサンプルを参考にしました。

入門 : Redis のデータ構造と概念 — Redis Documentation (Japanese Translation)

AzureのサンプルではLazyでコネクションを取るようにしていましたが、ここではそこまでしませんでした。

Azure Redis Cache を使用する方法 | Microsoft Docs

非同期で処理する

10,000件のオブジェクトを追加して、パフォーマンスも図ってみた

using System;
using StackExchange.Redis;
using System.Linq;
using System.Diagnostics;

namespace RedisSample
{
    class Program
    {
        static void Main(string[] args)
        {

            // 管理者コマンドを使用するために、接続文字列にallowAdmin=true"を追記
            ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost,allowAdmin=true");

            // データベースを取得
            IDatabase cache = redis.GetDatabase();

            // データベースを初期化
            var server = redis.GetServer("localhost", 6379);
            server.FlushAllDatabases();

            // キー生成のための数字を用意
            var range = Enumerable.Range(1, 10000);

            // 処理時間を測定
            Stopwatch sw = new Stopwatch();
            sw.Start();

            foreach (var index in range)
            {
                // 非同期でオブジェクトを追加
                cache.StringSetAsync($"number:{index}", $"result:{index}");
            }
            //すべての非同期処理を待つ
            cache.WaitAll();
            sw.Stop();

            //使用中のメモリを取得する
            var usedMemory = server.Info().Where(group => group.Key.Equals("Memory")).First().Where(c => c.Key.Equals("used_memory")).First();
            Console.WriteLine($"非同期処理処理終了後 / 使用メモリ {usedMemory.Key}:{usedMemory.Value} / 処理時間 {sw.ElapsedMilliseconds} ms / Keyの数 {server.Keys().Count()}");

            Console.ReadLine();
        }
    }
}

同様に同期処理でも図ってみたところ下記のような結果になりました。

同期処理:619ms 非同期処理:67ms

あくまでもローカルの参考値ですが、パイプラインの効果が出ていると感じられました。 あとやっぱりRedisって早いんだなって感じました。10,000件の追加が数十ms以内に終わりますもんね。 (Redisはシングルスレッドのため、非同期にしても追加する処理自体はかわらないはず・・・たぶん)

Pipelines and Multiplexers | StackExchange.Redis

参照

Azure Redis Cache を使用する方法 | Microsoft Docs

入門 : Redis のデータ構造と概念 — Redis Documentation (Japanese Translation)

c# - Flush/Empty db in StackExchange.Redis - Stack Overflow

とりあえず、今日はここまで。