引言: 

集合上两期.Net Core 微服务之Consul(一)(.Net Core 微服务之Consul(一)-CSDN博客) 。.Net Core 微服务之Consul(二)-集群搭建)(.Net Core 微服务之Consul(二)-集群搭建-CSDN博客

目录

一. Consul KV 存储

1. KV 存储介绍

1.1 数据模型

1.2 一致性和持久性

1.3 事务支持

1.4 版本控制

1.5 Watch 支持

1.6 ACL(访问控制列表)

2. .Net Core使用Consul进行KV存储

二. Consul 分布式锁

1. Consul 分布式锁简介

1.1 锁实现原理

1.2 锁的自动过期

1.3 锁的可重入性

1.4 Watch 支持

1.5 分布式系统中的应用场景

2. 分布式锁常见问题

2.1 分布式系统中的死锁

2.1.1 死锁的定义

2.1.2 死锁的原因

2.1.3 死锁的表现

2.1.4 Consul 死锁中的分布式锁解决方案

2.1.5 Consul 分布式锁原理

2.2 惊群效应

2.2.1 影响与问题

2.2.2 Consul 惊群中的分布式锁解决方案

2.3 脑裂 

2.3.1 脑裂的原因

2.3.2 Consul 脑裂中的解决方案

3. .Net Core使用Consul分布式锁

总结

.Net Core 微服务之Consul(三)-KV存储&分布式锁-LMLPHP

在分布式系统中,Consul 的 KV 存储和分布式锁功能是其非常重要的组成部分,本文将深入探讨这两个功能的实现细节、使用场景以及最佳实践。

一. Consul KV 存储

Consul 的 KV 存储是一个简单而强大的键值存储系统,被广泛用于分布式系统中的配置管理和共享数据。以下是关于 Consul KV 存储的一些关键点:

1. KV 存储介绍

1.1 数据模型

Consul 的 KV 存储提供了类似文件系统的键值存储模型,其中每个键都是一个路径,类似于 /path/to/key,而每个键对应的值可以是任意的字节序列。这种灵活性使得它不仅可以存储配置数据,还可以用于共享任意类型的数据。

1.2 一致性和持久性

Consul KV 存储提供强一致性和持久性。这意味着一旦数据被写入,它会被复制到 Consul 集群中的多个节点,并且在数据更新时保证所有节点都能读取到最新的数据版本。

1.3 事务支持

Consul 提供原子事务支持,允许在一个事务中执行多个操作,例如设置键值、获取键值、检查并操作等。这对于需要保证操作原子性的场景非常有用,可以避免因并发操作而导致的数据不一致问题。

1.4 版本控制

每个键值对都有一个版本号,这使得可以轻松地比较和控制数据的变更历史。版本控制对于跟踪配置更改或者实现乐观锁等机制非常有帮助。

1.5 Watch 支持

Consul 提供 Watch 功能,允许客户端监视特定键或前缀的更改。这使得应用程序可以实时响应配置变更而不需要轮询,从而降低了系统的资源消耗。

1.6 ACL(访问控制列表)

Consul 的 KV 存储支持 ACL,可以细粒度地控制谁可以读取或写入特定的键值对。这种安全机制对于保护敏感数据和限制特定服务的访问权限至关重要。

2. .Net Core使用Consul进行KV存储

  [Route("api/[controller]")]
  [ApiController]
  public class KVController : ControllerBase
  {
      protected ConsulOptions _options { get; set; }
      protected ILogger<KVController> _logger { get; set; }

      public KVController(IOptionsMonitor<ConsulOptions> options, ILogger<KVController> logger)
      {
          _options = options.CurrentValue;
          _logger = logger;
      }

      [HttpPost]
      public async Task KVPut()
      {
          using (ConsulClient client = new ConsulClient(x =>
          {
              x.Address = new Uri(_options.ConsulAddress);
          }))
          {
              var ws = await client.KV.Put(new KVPair("kvtest") { Value = Encoding.UTF8.GetBytes("100") });
              if (ws.StatusCode is HttpStatusCode.OK)
                  _logger.LogInformation("添加成功");
              else
                  _logger.LogError("添加失败");
          }
      }

      [HttpGet]
      public async Task KVGet()
      {
          using (ConsulClient client = new ConsulClient(x =>
          {
              x.Address = new Uri(_options.ConsulAddress);
          }))
          {
              var qr = await client.KV.Get("kvtest");
              if (qr.StatusCode is HttpStatusCode.OK)
                  _logger.LogInformation($"查询成功-{Encoding.UTF8.GetString(qr.Response.Value)}");
              else
                  _logger.LogError("查询失败");
          }
      }

      [HttpDelete]
      public async Task KVDelete()
      {
          using (ConsulClient client = new ConsulClient(x =>
          {
              x.Address = new Uri(_options.ConsulAddress);
          }))
          {
              var wr = await client.KV.Delete("kvtest");
              if (wr.StatusCode is HttpStatusCode.OK)
                  _logger.LogInformation("删除成功");
              else
                  _logger.LogError("删除失败&
07-23 12:04