1、什么是锁

  锁是为了解决多线程或者多进程资源竞争的问题。

  同一进程的多个线程资源竞争可以用lock解决。

  lock 关键字可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区。 如果其他线程尝试进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。

  

class Test
{
//定义一个私有成员变量,用于Lock
private static object lockobj = new object();
void DoSomething()
{
lock (lockobj)
{
//需要锁定的代码块
}
}
}

  多进程之间解决资源竞争问题我们则需要引入分布式锁。通过一个协调者来解决,通常的解决办法是通过redis来解决,这里不展开redis分布式锁的讨论。 接下来我们来聊聊如何自己实现一个分布式锁(不依赖于redis)。 

2、分布式锁是个什么鬼

  分布式锁是分布式、微服务中一个必然要讨论的话题。他为的是解决多进程多线程资源竞争的问题。

  

  下面我们以订单系统下单扣减库存为例聊一聊扣减库存的问题。

  三个客户KA、KB、KC同时下单购买物品P1,请求通过负载均衡器分发到订单服务A、订单服务B、订单服务C。这个时候三个服务同时要对数据库中的P1物品判断库存是否充足。假设库存剩余10个,KA需要购买6个、KB需要购买6个、KC需要购买6个。

  正常情况下服务A、B、C都查询了库存大于购买的数量,那么三个服务都判断可以下单。此时我们可以看到,她们都进行下单明显剩余库存不足18个,那么就会出现超卖的问题。那我们怎么办。我们第一时间会想到,不过在分布式环境下程序自带的Lock已经不能解决我们的问题。

  消息队列也可以解决这个问题,不过这里我们不讨论,我们要讨论的是用锁来解决。

这个时候我们需要一个协调者来协调三个服务同时只能有一个请求进入下单代码块。原理同本地锁一样(当一个线程位于代码的临界区时,另一个线程不会进入该临界区。 如果其他线程尝试进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放)。另外我们还需要注意的是,如果锁的拥有者出现问题,不能及时释放锁。那么就会导致其他服务一直等待。那么就会出现死锁的问题,因此我们也必须一如超时机制。在我们预设的处理时间内不能释放锁则需要协调者自动释放锁。防止出现死锁。

  下面我们来看看微服务框架Anno是如何实现一个分布式锁。

  如果对Anno微服务框架不了解可以看这里《【开源】.net微服务开发引擎Anno开源啦

2、实现一个分布式锁

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks; namespace ConsoleTest
{
using Anno.Const;
using Anno.EngineData;
using Anno.Loader;
using Anno.Rpc.Client;
using Anno.Rpc.Server;
using Autofac; public class DLockTest
{
public void Handle()
{
Init();
To:
List<Task> ts = new List<Task>();
Console.WriteLine("请输入线程数:");
int.TryParse(Console.ReadLine(), out int n);
for (int i = 0; i < n; i++)
{
var task = Task.Factory.StartNew(() => { DLTest1("Anno"); });
ts.Add(task);
//var taskXX = Task.Factory.StartNew(() => { DLTest1("Viper"); });
//ts.Add(taskXX); //var taskJJ = Task.Factory.StartNew(() => { DLTest1("Key001"); });
//ts.Add(taskJJ);
} Task.WaitAll(ts.ToArray());
goto To;
} private void DLTest1(string lk = "duyanming")
{
try
{
Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss:ffff} {System.Threading.Thread.CurrentThread.ManagedThreadId} DLTest1拉取锁({lk})");
using (DLock dLock = new DLock(lk, 10000))
{
Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss:ffff} {System.Threading.Thread.CurrentThread.ManagedThreadId} DLTest1进入锁({lk})");
System.Threading.Thread.Sleep(50);
} Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss:ffff} {System.Threading.Thread.CurrentThread.ManagedThreadId} DLTest1离开锁({lk})");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
void Init()
{
//SettingService.AppName = "DLockTest";
//SettingService.Local.IpAddress = "127.0.0.1";
//SettingService.Local.Port = 6660; IocLoader.GetAutoFacContainerBuilder().RegisterType(typeof(RpcConnectorImpl)).As(typeof(IRpcConnector)).SingleInstance();
IocLoader.Build();
DefaultConfigManager.SetDefaultConnectionPool(100, Environment.ProcessorCount * 2, 50);
DefaultConfigManager.SetDefaultConfiguration("DLockTest", "127.0.0.1", 6660, false);
}
}
}

GitHub地址:https://github.com/duyanming/Anno.Core/blob/master/test/ConsoleTest/DLockTest.cs

不同类型的锁可以同时进入相互不影响

 var task = Task.Factory.StartNew(() => { DLTest1("Anno"); });
ts.Add(task);
var taskXX = Task.Factory.StartNew(() => { DLTest1("Viper"); });
ts.Add(taskXX); var taskJJ = Task.Factory.StartNew(() => { DLTest1("Key001"); });
ts.Add(taskJJ);

上图我们开了12个进程同时进入DLTest1 方法,

using (DLock dLock = new DLock(lk, 10000))设置超时时间10秒。

关键代码:

 private void DLTest1(string lk = "duyanming")
{
try
{
Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss:ffff} {System.Threading.Thread.CurrentThread.ManagedThreadId} DLTest1拉取锁({lk})");
using (DLock dLock = new DLock(lk, 10000))
{
Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss:ffff} {System.Threading.Thread.CurrentThread.ManagedThreadId} DLTest1进入锁({lk})");
System.Threading.Thread.Sleep(50);
} Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss:ffff} {System.Threading.Thread.CurrentThread.ManagedThreadId} DLTest1离开锁({lk})");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}

所有源码都可以在 Anno中找到。

Anno核心源码:https://github.com/duyanming/Anno.Core  

Viper示例项目:https://github.com/duyanming/Viper  

体验地址:http://140.143.207.244/Home/Login

QQ交流群:478399354 

.netcore 微服务快速开发框架 Anno&Viper -分布式锁是个什么鬼的更多相关文章

  1. .netcore 微服务快速开发框架 Anno&Viper 注册中心 (服务上线下线预警通知)

    1.微服务时代,服务上线先预警通知 在微服务大行其道的今天,相信很多人都用上了微服务或者是微服务的概念也已经有了一个深刻的了解.今天我们不在这里展开阐述,今天我们要说的是微服务伴侣预警通知. 2.注册 ...

  2. Anno&Viper -分布式锁服务端怎么实现

    1.Anno简介 Anno是一个微服务框架引擎.入门简单.安全.稳定.高可用.全平台可监控.依赖第三方框架少.底层通讯RPC(Remote Procedure Call)采用稳定可靠经过无数成功项目验 ...

  3. 不死的小强 .net core 微服务 快速开发框架 Viper 限流

    1.Viper是什么? Viper 是.NET平台下的Anno微服务框架的一个示例项目.入门简单.安全.稳定.高可用.全平台可监控.底层通讯可以随意切换thrift grpc. 自带服务发现.调用链追 ...

  4. net core 微服务 快速开发框架 Viper 初体验2020-10-17

    1.Viper是什么? Viper 是.NET平台下的Anno微服务框架的一个示例项目.入门简单.安全.稳定.高可用.全平台可监控.底层通讯可以随意切换thrift grpc. 自带服务发现.调用链追 ...

  5. 基于SpringBoot-Dubbo的微服务快速开发框架

    简介: 基于Dubbo的分布式/微服务基础框架,为前端提供脚手架开发服务,结合前一篇--Web AP快速开发基础框架,可快速上手基于Dubbo的分布式服务开发,项目代码: https://github ...

  6. net core 微服务 快速开发框架

    dymDemo github 地址:https://github.com/duyanming/dymDemo dym 分布式开发框架 Demo 熔断 限流 事件总线(包括基于内存的.rabbitmq的 ...

  7. 一个轻量级的.Net Core微服务快速开发的轮子

    前言     Adnc是一个轻量级的.Net Core微服务快速开发框架,同时也可以应用于单体架构系统的开发.框架基于JWT认证授权.集成了一系列微服务配套组件,代码简洁.易上手.学习成本低.开箱即用 ...

  8. .NETCore微服务探寻(三) - 分布式日志

    前言 一直以来对于.NETCore微服务相关的技术栈都处于一个浅尝辄止的了解阶段,在现实工作中也对于微服务也一直没有使用的业务环境,所以一直也没有整合过一个完整的基于.NETCore技术栈的微服务项目 ...

  9. (1)学习笔记 ) ASP.NET CORE微服务 Micro-Service ---- 什么是微服务架构,.netCore微服务选型

    开发工具:VS2017 .Net Core 2.1 什么是微服务?单体结构: 缺点: 1)只能采用同一种技术,很难用不同的语言或者语言不同版本开发不同模块: 2)系统耦合性强,一旦其中一个模块有问题, ...

随机推荐

  1. bootstrap 按钮颜色属性

    bootstrap 按钮颜色属性有几种

  2. 为什么要小心使用 Task.Run

    昨天在博客园有园友问了我一个问题,是这样的: 先是半个月前 @碧水青荷 童鞋的一句话"大家都说不要随便 Task.Run(()=>{}) 这样写",当时没有想太多,这句话并没 ...

  3. socket阻塞与非阻塞,同步与异步,select,pool,epool

    概念理解 一.与I/O相关的五个重要概念 1. 第一个概念:用户空间与内核空间 1. 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方) 2. ...

  4. TCP的流量控制和阻塞控制

    流量控制和阻塞控制实例: 可以用一个例子来说明这种区别.设某个光纤网络的链路传输速率为1000Gbit/s.有一台巨型计算机向一台个人电脑以1Gbit/s的速率传送文件.显然,网络本身的带宽是足够大的 ...

  5. 因为一个Docker问题,我顺手整理从安装到常用命令操作手册

    今天,自己写了一部分业务代码,是常规代码的另外一种方式,不能在公司的服务器上测试,就自己在PC端搭建了一套和公司集群一样的模板,因为公司的业务模块的测试有单独的服务器(这一块还是我很稀罕的),但是,第 ...

  6. 图像处理术语解释:什么是PRGBA和Alpha预乘(Premultiplied Alpha )

    ☞ ░ 前往老猿Python博文目录 ░ Alpha预乘(Premultiplied Alpha)和PRGBA 一般来说四通道图像数据保存的都是ARGB或RGBA,其R.G.B值还没有进行任何透明化处 ...

  7. RedHat操作指令第2篇

    六.RPM包管理命令 主要功能 查询RPM软件.包文件的相关信息 安装.升级.卸载RPM软件包 维护RPM数据库信息 查询RPM软件信息 查询已安装的RPM软件信息 格式:rpm -q[子选项] [软 ...

  8. pytorch Dataset Dataloader用法(一个示例)

    from torch.utils.data import Dataset from torch.utils.data import DataLoader from torch.utils.data i ...

  9. js滑动到页面底部实现

    js实现 1.window.scrollTo(0,document.documentElement.clientHeight);  //js jq实现 2 .var windowHeight = pa ...

  10. day013|python之模块02&目录01

    1 from...import 1.1 概念 1.1.1 首次导入模块会发生的事 会触发模块的运行,产生一个模块的名称空间 将运行模块文件过程中产生的名字丢到模块额名称空间 在当前名称空间产生一个名字 ...