Redis(二)分布式锁与Redis集群搭建

@[toc]

一、 线程锁与分布式锁

  • 线程锁 单体项目

    • 单体项目

      • 步骤

        • 代码如下

           //定义静态全局锁
           private readonly static object _lock = new object();
          // 控制器中添加代码
            lock (_lock)
            { 
              Stock sto = new Stock();
              sto = demoDbContext.stock.Where(p => p.ID == 1).FirstOrDefault();
              if (sto.count == 0)
              {
                  Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "---秒杀结束,无库存");
                  return Ok("秒杀结束,无库存");
               }
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "--秒杀成功;");
                //库存减1
                sto.count = sto.count - 1;
                demoDbContext.SaveChanges();
            }
            return Ok("秒杀结束");
      • 数据库数量为10
        如图:
        在这里插入图片描述
      • 用jmeter并发10个线程
        如图:
        Redis(二)分布式锁与Redis集群搭建_第1张图片
  
- 运行结果如下:
  ![在这里插入图片描述](https://img-blog.csdnimg.cn/74dc100990c0461d9fba106606ccc8aa.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQEDnpZ7lhpzlhpnku6PnoIE=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
  • 分布式锁

    • 条件

      • 启动两个实例 5000/5001
      • Nginx
      • jmeter
    • 步骤

      • 核心代码

              public class RedisLock
              {
                  public readonly ConnectionMultiplexer connectionMultiplexer;
                  private IDatabase database = null; 
                  public RedisLock() 
                  {
                      connectionMultiplexer = ConnectionMultiplexer.Connect("127.0.0.1:6380");
                      database = connectionMultiplexer.GetDatabase(0);
                  }
                
                  /// 
                  /// 加锁
                  /// 
                  public void Lock() 
                  { 
                      while (true) //
                      {   
                          //redis_lock 锁名称
                          // Thread.CurrentThread.ManagedThreadId 线程名称
                          // TimeSpan.FromSeconds(10)  设置过期时间  防止死锁
                          bool flag = database.LockTake("redis_lock", Thread.CurrentThread.ManagedThreadId, TimeSpan.FromSeconds(10));
                          //true :加锁成功  false:加锁失败
                          if (flag) 
                          {
                              break;
                          }
                          Thread.Sleep(10);//防止死锁  等待时间  释放资源。
                      }
                  }
                  /// 
                  /// 释放锁
                  /// 
                  public void UnLock() 
                  {
                      database.LockRelease("redis_lock", Thread.CurrentThread.ManagedThreadId);
                      connectionMultiplexer.Close();
                  }
              }  

        控制器中使用

         [HttpGet]
          [Route("SubStock")]
          public IActionResult SubStock()
          {
        
              RedisLock redisLock = new RedisLock();
              redisLock.Lock();
              Stock sto = new Stock();
              sto = demoDbContext.stock.Where(p => p.ID == 1).FirstOrDefault();
              if (sto.count == 0)
              {
                  Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "---秒杀结束,无库存");
                  //redisLock.UnLock();
                  return Ok("秒杀结束,无库存");
              }
              Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "--秒杀成功;");
              //库存减1
              sto.count = sto.count - 1;
              demoDbContext.SaveChanges();
              redisLock.UnLock();
        
              return Ok("秒杀结束");
          }
      • 运行两个实例
        如图:
        Redis(二)分布式锁与Redis集群搭建_第2张图片
        Redis(二)分布式锁与Redis集群搭建_第3张图片
      • 启动Nginx
        如图:
        在这里插入图片描述
      • 数据库库存
        如图:
        在这里插入图片描述
      • jmeter并发10个线程
        Redis(二)分布式锁与Redis集群搭建_第4张图片
      • 运行结果如下
        Redis(二)分布式锁与Redis集群搭建_第5张图片
    • 分布式锁的使用场景
      当集群系统中修改某个字段值时使用分布式锁。
    • 分布式锁的设计思路
      比如并发两个进程,当第一个进程加锁后,第二个进程加锁会失败,会休眠(10毫秒),直到第一个进程执行完业务代码并释放锁,如果第一个进程处理业务代码超过10毫秒,redis的过期时间也是10毫秒,那么第二个进程进行加锁执行业务代码并释放锁。
      备注:休眠的毫秒数可根据自己业务代码定义,毫秒数最好和redis过期时间一致。
      ## 二、Redis集群
  • 第一代集群 主从集群

    • 如图:
      Redis(二)分布式锁与Redis集群搭建_第6张图片
    • 缺点
      只有一个master,当maset宕机后,整个redis集群系统无法使用。
  • 第二代集群 哨兵集群

    • 如图
      Redis(二)分布式锁与Redis集群搭建_第7张图片

      第二代集群比第一代集群多了一个sentinel监视的角色,当主节点宕机后,sentinel会从多个从节点中选择一个为主节点。

    • 缺点

      • 只有一个master,无法解决高并发写的问题。
      • 无法存储海量数据。
  • 第三代集群

    • 如图:
      Redis(二)分布式锁与Redis集群搭建_第8张图片
    • 优点与缺点

      • 优点

        • 解决高并发写。
        • 存储海量数据。
      • 缺点

        • 消耗资源比较大。
    • 实现

    • 步骤

      • 配置集群文件 (6个实例) 配置6个配置文件【并将6个配置拷贝到redis根目录下】 ==配置不能有中文注释也不行!!!!==

          port 6380                                         #端口
          bind 127.0.0.1                                    #IP地址
          appendonly yes                                    #数据保存格式为aof
          appendfilename "appendonly.6380.aof"              #数据保存文件
          cluster-enabled yes                               #是否开启集群
          cluster-config-file nodes.6380.conf               #集群节点配置文件
          cluster-node-timeout 15000                        #节点超时时间
          cluster-slave-validity-factor 10                  #验证slaver节点次数
          cluster-migration-barrier 1                       #
          cluster-require-full-coverage yes                 #master节点和slaver节点之间是否全量复制
      • 执行所有实例

        redis-server.exe redis.6380.conf 
        redis-server.exe redis.6381.conf 
        redis-server.exe redis.6382.conf 
        redis-server.exe redis.6383.conf 
        redis-server.exe redis.6384.conf 
        redis-server.exe redis.6385.conf 

        如图:
        Redis(二)分布式锁与Redis集群搭建_第9张图片
        Redis(二)分布式锁与Redis集群搭建_第10张图片
        Redis(二)分布式锁与Redis集群搭建_第11张图片
        Redis(二)分布式锁与Redis集群搭建_第12张图片
        Redis(二)分布式锁与Redis集群搭建_第13张图片
        Redis(二)分布式锁与Redis集群搭建_第14张图片

        • 安装 ruby

          ruby --version #验证是否安装成功
      • redis-cluster 驱动安装命令

          #进入 ruby安装目录bin文件下执行安装命令
          ruby gem install --local  D:\Assembly\redis\Windows\redis-cluster\redis-3.2.2.gem  #驱动文件路径
      • 执行分配主从工具脚本

        ruby redis-trib.rb create --replicas 1  127.0.0.1:6380  127.0.0.1:6381 127.0.0.1:6382   127.0.0.1:6383  127.0.0.1:6384  127.0.0.1:6385 
        #写入所有的实例地址和端口号
        # --replicas 1:是否分配3主3从  一个主节点和从节点 

        如图:
        Redis(二)分布式锁与Redis集群搭建_第15张图片

      • 查看是否分配成功
        当6个实例不停输出日志,说明已经分配成功。
    • redis集群内部关系结构图
      如图:
      Redis(二)分布式锁与Redis集群搭建_第16张图片

      在redis集群中,每个节点都是相互通信的,用的协议是Gossip协议。

    • redis集群内部数据存储原理

      • Slot槽 主节点有槽[平均分配] 从节点没有槽 总共有16384个槽

          ruby redis-trib.rb check 127.0.0.1:6380 
      • Hash算法
      • 取模算法
        当客户端将数据写入节点中时,节点会将key使用hash算法取到一个固定长度数值,然后对槽总数【16384】用取模算法进行取模,得到的数值后在到各个主节点中查看数值在哪个节点的槽数数值之间,在将数据写到那个主节点中。

你可能感兴趣的:(缓存redis集群分布式)