26

BookSleeveライブラリを介してRedisをフェッチする堅実なパターンを持っている人はいますか?

つまり:

BookSleeveの作者である@MarcGravellは、毎回接続を開いたり閉じたりするのではなく、アプリ全体で1つの接続を維持することを推奨しています。しかし、ネットワークの中断をどのように処理できますか?つまり、接続は最初は正常に開かれる可能性がありますが、一部のコードがRedisに対して読み取り/書き込みを試みると、接続が切断された可能性があり、接続を再度開く必要があります(開かない場合は正常に失敗します-しかしそれはあなたのデザインのニーズ次第です。)

一般的なRedis接続の開始と、各読み取り/書き込みの前に使用される一般的な「アライブ」チェック(+アライブでない場合はオプションのアウェイク)をカバーするコードスニペットを探しています。

この質問は問題に対する良い態度を示唆していますが、それは部分的であり(たとえば、失われた接続を回復しません)、その質問に対する受け入れられた答えは正しい方法を導きますが、具体的なコードを示していません。

このスレッドが確実な答えを得て、最終的に.NetアプリケーションでのBookSleeveの使用に関して一種のWikiになることを願っています。

-----------------------------

重要な更新(2014年3月21日):

-----------------------------

Marc Gravell(@MarcGravell)/ Stack Exchangeは最近、Booksleeveに代わるStackExchange.Redisライブラリをリリースました。この新しいライブラリは、とりわけ、内部で再接続を処理し、私の質問を冗長にします(つまり、Booksleeveや以下の私の答えでは冗長ではありませんが、今後の最善の方法は、新しいStackExchange.Redisライブラリの使用を開始することです)。

4

3 に答える 3

29

良い答えが得られなかったので、この解決策を思いつきました(BTWは@Simonと@Alexに答えてくれてありがとう!)。

参考までに、コミュニティの皆さんと共有したいと思います。もちろん、どんな修正でも大歓迎です。

using System;
using System.Net.Sockets;
using BookSleeve;

namespace Redis
{
    public sealed class RedisConnectionGateway
    {
        private const string RedisConnectionFailed = "Redis connection failed.";
        private RedisConnection _connection;
        private static volatile RedisConnectionGateway _instance;

        private static object syncLock = new object();
        private static object syncConnectionLock = new object();

        public static RedisConnectionGateway Current
        {
            get
            {
                if (_instance == null)
                {
                    lock (syncLock)
                    {
                        if (_instance == null)
                        {
                            _instance = new RedisConnectionGateway();
                        }
                    }
                }

                return _instance;
            }
        }

        private RedisConnectionGateway()
        {
            _connection = getNewConnection();
        }

        private static RedisConnection getNewConnection()
        {
            return new RedisConnection("127.0.0.1" /* change with config value of course */, syncTimeout: 5000, ioTimeout: 5000);
        }

        public RedisConnection GetConnection()
        {
            lock (syncConnectionLock)
            {
                if (_connection == null)
                    _connection = getNewConnection();

                if (_connection.State == RedisConnectionBase.ConnectionState.Opening)
                    return _connection;

                if (_connection.State == RedisConnectionBase.ConnectionState.Closing || _connection.State == RedisConnectionBase.ConnectionState.Closed)
                {
                    try
                    {
                        _connection = getNewConnection();
                    }
                    catch (Exception ex)
                    {
                        throw new Exception(RedisConnectionFailed, ex);
                    }
                }

                if (_connection.State == RedisConnectionBase.ConnectionState.Shiny)
                {
                    try
                    {
                        var openAsync = _connection.Open();
                        _connection.Wait(openAsync);
                    }
                    catch (SocketException ex)
                    {
                        throw new Exception(RedisConnectionFailed, ex);
                    }
                }

                return _connection;
            }
        }
    }
}
于 2012-01-08T13:38:14.840 に答える
2

他のシステム(ADO.NETなど)では、これは接続プールを使用して実現されます。新しいConnectionオブジェクトを実際に取得することはありませんが、実際にはプールから取得します。

プール自体は、呼び出し元のコードとは関係なく、新しい接続と切断された接続を管理します。ここでの考え方は、パフォーマンスを向上させ(新しい接続の確立にはコストがかかる)、ネットワークの問題に耐えることです(サーバーがダウンしている間は呼び出し元のコードが失敗しますが、オンラインに戻ると再開します)。実際には、接続の「タイプ」ごとに、AppDomainごとに1つのプールがあります。

この動作は、ADO.NET接続文字列を見ると発生します。たとえば、SQL Server接続文字列(ConnectionStringプロパティ)には、「プール」、「最大プールサイズ」、「最小プールサイズ」などの概念があります。これは、必要に応じて現在のAppDomainプールをプログラムでリセットするために使用されるClearAllPoolsメソッドでもあります。例えば。

BookSleeveコードを調べているこの種の機能に近いものは見当たりませんが、次のリリースであるBookSleeveRoadMapで計画されているようです。

それまでの間、RedisConnectionには、デッドになったときに検出するために使用できるエラーイベントがあるため、独自の接続プールを作成できると思います。

于 2011-12-28T13:45:56.770 に答える
2

私はC#プログラマーではありませんが、問題の見方は次のとおりです。

  1. redis接続とRedisコマンドを表すラムダ式をパラメーターとして受け取るジェネリック関数をコーディングします

  2. Redisコマンドを実行しようとすると、接続の問題を指摘する例外が発生する場合は、接続を再初期化して操作を再試行します

  3. 例外が発生しない場合は、結果を返すだけです

ある種の擬似コードを次に示します。

function execute(redis_con, lambda_func) {
    try {
        return lambda_func(redis_con)
    }
    catch(connection_exception) {
        redis_con = reconnect()
        return  lambda_func(redis_con)
    }
}
于 2012-01-06T23:24:51.027 に答える