Требуется ли синхронизация на уровне кода при вставке или удалении значений из кэша Azure Redis?

Я использую следующий одноэлементный класс для получения/установки/удаления значений из кэша Azure Redis для одной из моих личных разработок.

using StackExchange.Redis;
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace PoC
{
    public sealed class CacheManager
    {
        public static object mutex = new object();

        public static string EndPoint { get; set; }
        public static string Password { get; set; }
        public static bool UseSsl { get; set; }
        public static int ConnectRetry { get; set; }
        public static int KeepAlive { get; set; }
        public static int ConnectTimeout { get; set; }

        private static ConfigurationOptions ConfigurationOptions;

        private static readonly CacheManager instance = new CacheManager();

        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static CacheManager() { }

        private CacheManager()
        {
            ConfigurationOptions = new ConfigurationOptions
            {
                Password = Password,
                Ssl = UseSsl,
                AbortOnConnectFail = false,
                ConnectRetry = ConnectRetry,
                KeepAlive = KeepAlive,
                ConnectTimeout = ConnectTimeout
            };
        }

        public static CacheManager Instance { get { return instance; } }

        public static string ConnectionString { get; set; }

        Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
        {
            return ConnectionMultiplexer.Connect(ConfigurationOptions);
        });

        IDatabase Database => lazyConnection.Value.GetDatabase();


        public void Set<T>(string key, T value)
        {
            lock (mutex)
            {
                Database.StringSet(key, ToByteArray(value));
            }
        }

        public T Get<T>(string key)
        {
            T result = FromByteArray<T>(Database.StringGet(key));
            return result;
        }

        public bool Remove(string key)
        {
            lock (mutex)
            {
                var removed = Database.KeyDelete(key);
                return removed;
            }
        }

        public byte[] ToByteArray<T>(T obj)
        {
            if (obj == null)
                return null;
            BinaryFormatter bf = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream())
            {
                bf.Serialize(ms, obj);
                return ms.ToArray();
            }
        }

        public T FromByteArray<T>(byte[] data)
        {
            if (data == null)
                return default(T);
            BinaryFormatter bf = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream(data))
            {
                object obj = bf.Deserialize(ms);
                return (T)obj;
            }
        }
    }
}


Здесь я использовал блокировку при вставке значений в базу данных или удалении значений из базы данных. Но из следующего поста я узнал, что Redis — это однопоточная база данных, и все операции атомарны.

Есть ли какой-либо механизм блокировки в Кэш Azure Redis при обновлении элемента?

Поэтому я считаю, что блокировка, которую я использовал, не нужна и может привести к некоторым проблемам с производительностью. Пожалуйста, поправьте меня, если я ошибаюсь. Я устанавливаю переменные (EndPoint, Password и т. д.) один раз в событии Application_Start. Был бы признателен за помощь.


person Arka Chatterjee    schedule 12.06.2020    source источник


Ответы (1)


Вы можете узнать, как использовать WATCH в Redis. https://stackexchange.github.io/StackExchange.Redis/Transactions.html

WATCH key  
isFieldExists = HEXISTS key, field  
if isFieldExists is 1  
MULTI  
HSET key, field, value  
EXEC  
else  
UNWATCH  
return isFieldExists

Пример:

var newId = CreateNewId();
var tran = db.CreateTransaction();
tran.AddCondition(Condition.HashNotExists(custKey, "UniqueID"));
tran.HashSetAsync(custKey, "UniqueID", newId);
bool committed = tran.Execute();
person Jason Pan    schedule 12.06.2020
comment
Это не отвечает на мой вопрос. Однако должны ли мы применять транзакции во время операций вставки/удаления? Это противоречит тому, что сказано здесь - redis.io/topics/latency#single -threaded-nature-of-redis. Нам все еще нужно использовать блокировку/транзакции? - person Arka Chatterjee; 12.06.2020
comment
Я имею в виду, что вам не нужно использовать блокировку, просто используйте WATCH для фиксации транзакции. - person Jason Pan; 12.06.2020
comment
Спасибо Джейсон. Как мне это сделать в примере кода, который я разместил выше. Нужно ли мне вносить какие-либо изменения в этот код, чтобы он работал идеально (после снятия блокировки)? Пожалуйста, предложите. - person Arka Chatterjee; 12.06.2020