Adhesive框架系列文章--分布式组件客户端模块使用

简介: Memcached是一个很常见的分布式组件,现在有很多.NET下开源的Memcached组件的客户端实现,比如EnyimMemcachedClient。在Adhesive框架中实现了一个分布式组件客户端,同时也实现了第一个具体的客户端,也就是Memcached。

Memcached是一个很常见的分布式组件,现在有很多.NET下开源的Memcached组件的客户端实现,比如EnyimMemcachedClient。在Adhesive框架中实现了一个分布式组件客户端,同时也实现了第一个具体的客户端,也就是Memcached。与其它实现不同的是,这里我们提供了Memcached二进制协议的完整实现,并且也实现了一些特色功能,进一步封装了Memcached的一些基础API。

 

要使用Adhesive.DistributedComponentClient,首先免不了进行配置。和框架的其它模块一样,这里我们也使用了配置服务:

image

进一步查看:

image

在这里我们定义了一个TestMemcachedCluster:

image

对于每一个集群,需要配置其名字以及尝试恢复节点的时间间隔。也就是在节点连接不上的时候,多久尝试进行一次节点的恢复。在Adhesive的实现中,一个集群下应该有多个节点,节点的分配根据Key进行一致性哈希,如果某个节点不可用,进行节点的重新分配,并不会影响程序的使用,当然由于重分配,必定会有1/N的数据丢失。在节点恢复后,又会进行重新分配。下面看一下节点的配置:

image

在这里定义了四个节点,随便点进去一个看看:

image

这里定义了:

1、节点名字

2、节点地址

3、节点的权重:所谓权重就是在进行Key到Node分配时候的权重,权重越高分配的Key越高,在使用的时候负载也就越重。对于Memcached来说,可以把内存少的节点权重设置低一些。

4、最大的连接数:连接池中允许的最大连接数

5、最小的连接数:连接池中保留的最小连接数

6、最大闲置时间:闲置时间过长的连接会被回收

7、最大忙碌时间:忙碌时间过长的连接会被强制关闭

8、连接超时时间

9、发送数据超时时间

10、接受数据超时时间

11、连接池维护时间间隔:连接池在维护的时候会回收闲置过长的连接,会关闭忙碌过长的连接,会补充连接到最小连接数。

在某些情况下,您可能希望独立使用这个组件,也不是依赖配置服务,那么可以如下操作:

找到DistributedServerConfiguration.cs,把private static DistributedServerConfigurationEntity GetConfig()中的:

var defaultConfig = GetDefaultConfig();
var config = configService.GetConfigItemValue(true, "DistributedServerConfiguration", defaultConfig);

替换为:

var defaultConfig = GetDefaultConfig(); 
var config = LocalConfigService.GetConfig(defaultConfig);

也就是使用本地配置服务来替代通用配置服务。对于本地配置服务会在程序的Config目录下生成.config的配置文件,这样就可以不依赖配置服务直接启动程序,比如:

 

<?xml version="1.0" encoding="utf-8"?>
<DistributedServerConfigurationEntity xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ClientClusterConfigurations>
    <item>
      <key>
        <string>TestMemcachedCluster</string>
      </key>
      <value>
        <ClientClusterConfiguration>
          <Name>TestMemcachedCluster</Name>
          <TryRecoverNodeInterval>00:00:10</TryRecoverNodeInterval>
          <ClientNodeConfigurations>
            <item>
              <key>
                <string>MemcachedNode1</string>
              </key>
              <value>
                <ClientNodeConfiguration>
                  <Name>MemcachedNode1</Name>
                  <Address>192.168.135.222:12000</Address>
                  <Weight>Medium</Weight>
                  <MaxConnections>50</MaxConnections>
                  <MinConnections>5</MinConnections>
                  <MaxIdleTime>00:01:00</MaxIdleTime>
                  <MaxBusyTime>00:01:00</MaxBusyTime>
                  <ConnectTimeout>00:00:05</ConnectTimeout>
                  <SendTimeout>00:00:05</SendTimeout>
                  <ReceiveTimeout>00:00:05</ReceiveTimeout>
                  <MaintenanceInterval>00:00:30</MaintenanceInterval>
                </ClientNodeConfiguration>
              </value>
            </item>
            <item>
              <key>
                <string>MemcachedNode2</string>
              </key>
              <value>
                <ClientNodeConfiguration>
                  <Name>MemcachedNode2</Name>
                  <Address>192.168.135.222:12001</Address>
                  <Weight>Medium</Weight>
                  <MaxConnections>50</MaxConnections>
                  <MinConnections>5</MinConnections>
                  <MaxIdleTime>00:01:00</MaxIdleTime>
                  <MaxBusyTime>00:01:00</MaxBusyTime>
                  <ConnectTimeout>00:00:05</ConnectTimeout>
                  <SendTimeout>00:00:05</SendTimeout>
                  <ReceiveTimeout>00:00:05</ReceiveTimeout>
                  <MaintenanceInterval>00:00:30</MaintenanceInterval>
                </ClientNodeConfiguration>
              </value>
            </item>
            <item>
              <key>
                <string>MemcachedNode3</string>
              </key>
              <value>
                <ClientNodeConfiguration>
                  <Name>MemcachedNode3</Name>
                  <Address>192.168.135.221:12000</Address>
                  <Weight>Medium</Weight>
                  <MaxConnections>50</MaxConnections>
                  <MinConnections>5</MinConnections>
                  <MaxIdleTime>00:01:00</MaxIdleTime>
                  <MaxBusyTime>00:01:00</MaxBusyTime>
                  <ConnectTimeout>00:00:05</ConnectTimeout>
                  <SendTimeout>00:00:05</SendTimeout>
                  <ReceiveTimeout>00:00:05</ReceiveTimeout>
                  <MaintenanceInterval>00:00:30</MaintenanceInterval>
                </ClientNodeConfiguration>
              </value>
            </item>
            <item>
              <key>
                <string>MemcachedNode4</string>
              </key>
              <value>
                <ClientNodeConfiguration>
                  <Name>MemcachedNode4</Name>
                  <Address>192.168.135.221:12001</Address>
                  <Weight>Medium</Weight>
                  <MaxConnections>50</MaxConnections>
                  <MinConnections>5</MinConnections>
                  <MaxIdleTime>00:01:00</MaxIdleTime>
                  <MaxBusyTime>00:01:00</MaxBusyTime>
                  <ConnectTimeout>00:00:05</ConnectTimeout>
                  <SendTimeout>00:00:05</SendTimeout>
                  <ReceiveTimeout>00:00:05</ReceiveTimeout>
                  <MaintenanceInterval>00:00:30</MaintenanceInterval>
                </ClientNodeConfiguration>
              </value>
            </item>
          </ClientNodeConfigurations>
        </ClientClusterConfiguration>
      </value>
    </item>
  </ClientClusterConfigurations>
</DistributedServerConfigurationEntity>

在介绍了配置之后,就来介绍如何使用客户端,首先可以获得一个集群:

var client = MemcachedClient.GetClient("TestMemcachedCluster");

然后可以通过client调用各种API了:

image

1、清空数据:

Dictionary<string, bool> Flush(TimeSpan expire)

Dictionary<string, bool> Flush()

这里提供了两个重载。可以清空整个集群所有数据,也可以清空一定未来一定时间内将会过期的所有数据。

2、获取服务端版本:

Dictionary<string, string> Version()

将会列出每一个节点的版本号

3、获取服务端状态:

Dictionary<string, Dictionary<string, string>> Stat(StatType statType)

Dictionary<string, Dictionary<string, string>> Stat()

在这里提供了两个重载,可以获取指定类型的状态数据,也可以获取所有状态数据。StatType 定义如下:

    public enum StatType
    {
        General = 0,
        Item = 1,
        Setting = 2,
    }

要注意,在这里同样是按照节点分组的。

4、获取数据的操作:

string Get(string key)

T Get<T>(string key)

string Get(string key, out ulong version)

T Get<T>(string key, out ulong version)

在这里提供了获取纯字符串和获取泛型类型两组方法,也提供了仅仅获取值以及获取值和版本号两组方法。在并发状态下,很可能我们在获取一个Value之后进行了一些修改,但在Set到Memcached的时候已经被其它人Set过一次了,那么我们可以通过Get时候获取到的版本号来确保Set的时候的版本和之前Get时候的版本一致:

 ulong version = 0;
                    var key = Guid.NewGuid().ToString();
                    Assert.IsTrue(client.Add(key, stringValue, expire, version));
                    Assert.AreEqual(stringValue, client.Get(key, out version));
                    Assert.IsTrue(client.Replace(key, stringValue, version));
                    Assert.IsFalse(client.Replace(key, stringValue, version));

上面的测试代码表明在进行一次操作之后版本号会修改,再使用老的版本号进行Replace操作将会失败。

5、存入数据的操作:

bool Set(string key, string value)

bool Set(string key, string value, ulong version)

bool Set(string key, string value, TimeSpan expire)

bool Set(string key, string value, TimeSpan expire, ulong version)

bool Set<T>(string key, T value)

bool Set<T>(string key, T value, ulong version)

bool Set<T>(string key, T value, TimeSpan expire)

bool Set<T>(string key, T value, TimeSpan expire, ulong version)

对于泛型和纯字符串的重载,每一组中都会有普通的Set、检查版本号的Set、设置超时时间的Set以及设置超时时间+检查版本号的Set。

对于Set操作来说,如果Key存在,那么就会替换已有的Value,如果Key不存在就会增加一组KeyValue。

如果赋值了超时时间,那么超过这个时间值就或Get不到,当然由于memcached的限制,超时时间不能超过30天。

6、替换数据的操作:

bool Replace(string key, string value)

bool Replace(string key, string value, ulong version)

bool Replace(string key, string value, TimeSpan expire)

bool Replace(string key, string value, TimeSpan expire, ulong version)

bool Replace<T>(string key, T value)

bool Replace<T>(string key, T value, ulong version)

bool Replace<T>(string key, T value, TimeSpan expire)

bool Replace<T>(string key, T value, TimeSpan expire, ulong version)

方法签名和Set基本一致,只不过要注意,如果Key不存在,那么Replace会失败,也就是返回false。

 var key = Guid.NewGuid().ToString();
                    Assert.IsFalse(client.Replace(key, stringValue));
                    Assert.IsTrue(client.Set(key, ""));
                    Assert.IsTrue(client.Replace(key, stringValue));
                    Assert.AreEqual(client.Get(key), stringValue);

7、增加数据的操作:

bool Add(string key, string value)

bool Add(string key, string value, ulong version)

bool Add(string key, string value, TimeSpan expire)

bool Add(string key, string value, TimeSpan expire, ulong version)

bool Add<T>(string key, T value)

bool Add<T>(string key, T value, ulong version)

bool Add<T>(string key, T value, TimeSpan expire)

bool Add<T>(string key, T value, TimeSpan expire, ulong version)

方法签名和Set基本一致,只不过要注意,如果Key已经存在,那么Add会失败,也就是返回false。

 var key = Guid.NewGuid().ToString();
                    Assert.IsTrue(client.Set(key, ""));
                    Assert.IsFalse(client.Add(key, stringValue, expire));
                    Assert.IsTrue(client.Delete(key));
                    Assert.IsTrue(client.Add(key, stringValue, expire));
                    Assert.AreEqual(client.Get(key), stringValue);

8、递增的操作:

ulong? Increment(string key, ulong amount)

ulong? Increment(string key, ulong amount, ulong version)

ulong? IncrementWithInit(string key, ulong seed, TimeSpan expire, ulong amount)

ulong? IncrementWithInit(string key, ulong seed, ulong amount)

ulong? IncrementWithInit(string key, ulong seed, TimeSpan expire, ulong amount, ulong version)

ulong? IncrementWithInit(string key, ulong seed, ulong amount, ulong version)

在这里主要有两组操作,第一组是增加一个已有的值,第二组是增加一个已有的值或者初始化值。先来看第一组的测试代码:

 var key = Guid.NewGuid().ToString();
                    var result = client.Increment(key, 10);
                    Assert.IsFalse(result.HasValue);
                    Assert.IsTrue(client.Set(key, i));
                    result = client.Increment(key, 10);
                    Assert.IsTrue(result.HasValue);
                    Assert.AreEqual(result.Value, (ulong)i + 10);

第一次调用的时候由于没有值会得到一个空值。在设置了值之后再调用就会得到值了。再来看看第二组的测试代码:

var key = Guid.NewGuid().ToString();
                    var result = client.IncrementWithInit(key, (ulong)i, expire, 10);
                    Assert.IsTrue(result.HasValue);
                    Assert.AreEqual(result.Value, (ulong)i);
                    result = client.IncrementWithInit(key, (ulong)i, expire, 10);
                    Assert.IsTrue(result.HasValue);
                    Assert.AreEqual(result.Value, (ulong)i + 10);

使用i进行初始化,并且递增步进设置为10,第一次由于没有值结果应该就是i,第二次则是i+10了。对于IncrementWithInit,由于附带了初始化Value的功能,所以我们可以提供一个过期时间。

9、和递增相对应的递减操作:

ulong? Decrement(string key, ulong amount)

ulong? Decrement(string key, ulong amount, ulong version)

ulong? DecrementWithInit(string key, ulong seed, TimeSpan expire, ulong amount)

ulong? DecrementWithInit(string key, ulong seed, ulong amount)

ulong? DecrementWithInit(string key, ulong seed, TimeSpan expire, ulong amount, ulong version)

ulong? DecrementWithInit(string key, ulong seed, ulong amount, ulong version)

这里就不过多介绍了,递减和递增相对应,为seed减少一个amount。

10、为字符串加值:

bool Append(string key, string value)

bool Prepend(string key, string value)

分别是把另一个字符串value加到key对应的字符串的后面和前面:

var key = Guid.NewGuid().ToString();
                    Assert.IsTrue(client.Set(key, stringValue, expire));
                    Assert.IsTrue(client.Append(key, "你好"));
                    Assert.AreEqual(stringValue + "你好", client.Get(key));
var key = Guid.NewGuid().ToString();
                    Assert.IsTrue(client.Set(key, stringValue, expire));
                    Assert.IsTrue(client.Prepend(key, "你好"));
                    Assert.AreEqual("你好" + stringValue, client.Get(key));

11、删除一个Value:

bool Delete(string key)

这个没啥好说的,删除后将会Get不到这个Key。

12、快速操作:

由于Set和Delete很常用,并且我们往往不需要知道操作的返回值也允许操作发生失败,因此在这里提供了FastSet和FastDelete的功能。对于这些API,不提供返回值,只是尝试进行Set和Delete操作。相比普通的Set和Delete操作,Fast版本可以有10%以上的性能提高,因为我们不会解析Response的消息,并且在不出错的情况下,Memcached服务端也不会返回Response消息。

void FastSet(string key, string value)

void FastSet(string key, string value, ulong version)

void FastSet(string key, string value, TimeSpan expire)

void FastSet(string key, string value, TimeSpan expire, ulong version)

void FastSet<T>(string key, T value)

void FastSet<T>(string key, T value, ulong version)

void FastSet<T>(string key, T value, TimeSpan expire)

void FastSet<T>(string key, T value, TimeSpan expire, ulong version)

void FastDelete(string key)

 

上面介绍的这些API其实都是Memcached服务端提供的API,下面会介绍一些利用这些API提供的特色功能,进一步方便使用者。在这里我们仅仅介绍使用,不会介绍其实现,大家可以思考一下,如何利用之前提到的12个API来完成下面的功能。

1、判断Key是否存在:

bool Exists(string key)

2、Get+Set:

也就是如果Key存在的话则获取,如果不存在的话,使用Set值为回调方法提供的值,最后返回值

string GetAndSet(string key, Func<string> getValue, TimeSpan expire)

string GetAndSet(string key, Func<string> getValue)

T GetAndSet<T>(string key, Func<T> getValue, TimeSpan expire)

T GetAndSet<T>(string key, Func<T> getValue)

string GetAndSetWhen(string key, Func<string> getValue, TimeSpan exipre, Func<bool> condition)

string GetAndSetWhen(string key, Func<string> getValue, Func<bool> condition)

T GetAndSetWhen<T>(string key, Func<T> getValue, Func<bool> condition)

T GetAndSetWhen<T>(string key, Func<T> getValue, TimeSpan expire, Func<bool> condition)

这里还定义了一组GetAndSetWhen方法,也就是满足condition的时候才进行值的Set。

我们来看一个应用:

   private int InternalGetDataCount(string typeFullName, string databaseName, string tableName, string columnName, DateTime begin, DateTime end, IMongoQuery filterquery)
        {
            try
            {
                var count = memcachedClient.GetAndSetWhen<int?>(GetMemcachedKey(typeFullName, databaseName, tableName, columnName,
                    begin.ToString("yyyyMMddHHmmss"), end.ToString("yyyyMMddHHmmss"), filterquery), () =>
                    {
                        var query = Query.And(Query.LT(columnName, end).GTE(begin), filterquery);
                        var server = CreateSlaveMongoServer(typeFullName);
                        var database = server.GetDatabase(databaseName);
                        var collection = database.GetCollection(tableName);
                        var c = collection.Count(query);
                        Console.WriteLine(string.Format("Db {0} {1} {2} {3} {4} {5} {6} {7}", typeFullName, databaseName, tableName, columnName,
                           begin.ToString("yyyyMMddHHmmss"), end.ToString("yyyyMMddHHmmss"), filterquery == null ? "" : filterquery.ToString(), c));
                        return c;
                    }, TimeSpan.FromDays(1), () => DateTime.Now > end);
                return count.Value;
            }
            catch (Exception ex)
            {
                LocalLoggingService.Error(ex.ToString());
                throw;
            }
        }

比如在这里,我们从Mongodb数据库获取数据量,并希望把结果缓存在Memcached中。但是我们不希望在结束时间大于当前时间的情况下缓存值,因为只有过去时间获取的统计值才不会变动,才可以缓存下来。这是就可以使用GetAndSetWhen了。

3、分布式锁

IDisposable AcquireLock(string key, TimeSpan timeOut)

Memcached由于是单点,因此很适合作为分布式锁,测试代码如下:

 var timeoutCount = 0;
                var key = Guid.NewGuid().ToString();
                Parallel.For(0, 10, i =>
                {
                    try
                    {
                        using (var locker = client.AcquireLock(key, TimeSpan.FromMilliseconds(100)))
                        {
                            Thread.Sleep(1000);
                        }
                    }
                    catch (TimeoutException)
                    {
                        Interlocked.Increment(ref timeoutCount);
                    }
                });

                Assert.AreEqual(timeoutCount, 9);

在这里,我们在获得了锁之后等待1秒,并且允许锁的超时时间为10毫秒。这样的话,在并发情况下,只应该有一次调用可以成功,其它9次都会失败,失败的时候会抛出TimeoutException异常。

4、列表操作:

List<string> GetList(string listKey, int pageSize, int pageIndex)

List<string> GetList(string listKey)

List<T> GetList<T>(string listKey, int pageSize, int pageIndex)

List<T> GetList<T>(string listKey)

 

bool SetListItem(string listKey, string itemKey, string itemValue)

bool SetListItem(string listKey, string itemKey, string itemValue, TimeSpan expire)

bool SetListItem<T>(string listKey, string itemKey, T itemValue, TimeSpan expire)

bool SetListItem<T>(string listKey, string itemKey, T itemValue)

 

bool DeleteListItem(string listKey, string itemKey)

有的时候,我们会在Memcached中存一组数据列表数据,并且又不希望在修改项的时候获取整个列表然后修改后回存回去。这个时候就需要保存多个KeyValue,并且使用一个KeyValue来存放列表中所有的Key。这组API封装了其中的实现。允许我们:

1)获取列表所有数据

2)分页方式获取部分数据

3)设置某个项

4)删除某个项

测试代码如下:

var listKey = Guid.NewGuid().ToString();
                var pageIndex = 2;
                var pageSize = 10;

                Parallel.For(0, 100, i =>
                {
                    var itemKey = Guid.NewGuid().ToString();
                    client.SetListItem(listKey, itemKey, new User(i), TimeSpan.FromMinutes(10));
                });
                var value = client.GetList<User>(listKey, pageSize, pageIndex);
                Assert.AreEqual(value.Count, pageSize);
                Assert.AreEqual(value.First().GetType(), typeof(User));

5、批量获取操作:

Dictionary<string, string> GetMultiple(IList<string> keys)

Dictionary<string, T> GetMultiple<T>(IList<string> keys)

也就是直接获取一组Key的值。由于提供的Key可能分布在多个节点上,因此在这里我们使用并行方式同时到都个节点上获取相应的值。测试代码如下:

 var keys = new System.Collections.Concurrent.ConcurrentBag<string>();
                Parallel.For(0, 1000, i =>
                {
                    var key = Guid.NewGuid().ToString();
                    Assert.IsTrue(client.Set(key, new User(i), TimeSpan.FromMinutes(10)));
                    keys.Add(key);
                });

                var value = client.GetMultiple<User>(keys.ToList());
                Assert.AreEqual(value.Count, keys.Count);
                foreach (var item in value)
                {
                    Assert.AreEqual(item.Value.GetType(), typeof(User));
                }

 

至此,我们介绍了所有API的使用,可以直接查看源代码中的Adhesive.DistributedComponentClient.Test项目以及Adhesive.DistributedComponentClient.UnitTest来了解如何使用。经过测试,Adhesive的这个Memcached客户端的实现和Enyim的实现在性能上有5%左右的提高,并且API更丰富(后面那些特色API)。

作者: lovecindywang
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
|
10天前
|
存储 监控 数据可视化
常见的分布式定时任务调度框架
分布式定时任务调度框架用于在分布式系统中管理和调度定时任务,确保任务按预定时间和频率执行。其核心概念包括Job(任务)、Trigger(触发器)、Executor(执行器)和Scheduler(调度器)。这类框架应具备任务管理、任务监控、良好的可扩展性和高可用性等功能。常用的Java生态中的分布式任务调度框架有Quartz Scheduler、ElasticJob和XXL-JOB。
189 66
|
3天前
|
数据采集 人工智能 分布式计算
MaxFrame:链接大数据与AI的高效分布式计算框架深度评测与实践!
阿里云推出的MaxFrame是链接大数据与AI的分布式Python计算框架,提供类似Pandas的操作接口和分布式处理能力。本文从部署、功能验证到实际场景全面评测MaxFrame,涵盖分布式Pandas操作、大语言模型数据预处理及企业级应用。结果显示,MaxFrame在处理大规模数据时性能显著提升,代码兼容性强,适合从数据清洗到训练数据生成的全链路场景...
15 5
MaxFrame:链接大数据与AI的高效分布式计算框架深度评测与实践!
|
17天前
|
分布式计算 大数据 数据处理
技术评测:MaxCompute MaxFrame——阿里云自研分布式计算框架的Python编程接口
随着大数据和人工智能技术的发展,数据处理的需求日益增长。阿里云推出的MaxCompute MaxFrame(简称“MaxFrame”)是一个专为Python开发者设计的分布式计算框架,它不仅支持Python编程接口,还能直接利用MaxCompute的云原生大数据计算资源和服务。本文将通过一系列最佳实践测评,探讨MaxFrame在分布式Pandas处理以及大语言模型数据处理场景中的表现,并分析其在实际工作中的应用潜力。
55 2
|
2月前
|
存储 Java 关系型数据库
在Spring Boot中整合Seata框架实现分布式事务
可以在 Spring Boot 中成功整合 Seata 框架,实现分布式事务的管理和处理。在实际应用中,还需要根据具体的业务需求和技术架构进行进一步的优化和调整。同时,要注意处理各种可能出现的问题,以保障分布式事务的顺利执行。
89 6
|
2月前
|
消息中间件 运维 数据库
Seata框架和其他分布式事务框架有什么区别
Seata框架和其他分布式事务框架有什么区别
36 1
|
3月前
|
NoSQL Java Redis
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
Redis分布式锁在高并发场景下是重要的技术手段,但其实现过程中常遇到五大深坑:**原子性问题**、**连接耗尽问题**、**锁过期问题**、**锁失效问题**以及**锁分段问题**。这些问题不仅影响系统的稳定性和性能,还可能导致数据不一致。尼恩在实际项目中总结了这些坑,并提供了详细的解决方案,包括使用Lua脚本保证原子性、设置合理的锁过期时间和使用看门狗机制、以及通过锁分段提升性能。这些经验和技巧对面试和实际开发都有很大帮助,值得深入学习和实践。
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
|
5月前
|
NoSQL Redis
基于Redis的高可用分布式锁——RedLock
这篇文章介绍了基于Redis的高可用分布式锁RedLock的概念、工作流程、获取和释放锁的方法,以及RedLock相比单机锁在高可用性上的优势,同时指出了其在某些特殊场景下的不足,并提到了ZooKeeper作为另一种实现分布式锁的方案。
141 2
基于Redis的高可用分布式锁——RedLock
|
1月前
|
存储 NoSQL Java
使用lock4j-redis-template-spring-boot-starter实现redis分布式锁
通过使用 `lock4j-redis-template-spring-boot-starter`,我们可以轻松实现 Redis 分布式锁,从而解决分布式系统中多个实例并发访问共享资源的问题。合理配置和使用分布式锁,可以有效提高系统的稳定性和数据的一致性。希望本文对你在实际项目中使用 Redis 分布式锁有所帮助。
105 5
|
2月前
|
NoSQL Java 数据处理
基于Redis海量数据场景分布式ID架构实践
【11月更文挑战第30天】在现代分布式系统中,生成全局唯一的ID是一个常见且重要的需求。在微服务架构中,各个服务可能需要生成唯一标识符,如用户ID、订单ID等。传统的自增ID已经无法满足在集群环境下保持唯一性的要求,而分布式ID解决方案能够确保即使在多个实例间也能生成全局唯一的标识符。本文将深入探讨如何利用Redis实现分布式ID生成,并通过Java语言展示多个示例,同时分析每个实践方案的优缺点。
71 8
|
2月前
|
NoSQL Redis
Redis分布式锁如何实现 ?
Redis分布式锁通过SETNX指令实现,确保仅在键不存在时设置值。此机制用于控制多个线程对共享资源的访问,避免并发冲突。然而,实际应用中需解决死锁、锁超时、归一化、可重入及阻塞等问题,以确保系统的稳定性和可靠性。解决方案包括设置锁超时、引入Watch Dog机制、使用ThreadLocal绑定加解锁操作、实现计数器支持可重入锁以及采用自旋锁思想处理阻塞请求。
61 16