.netcore 微服务快速开发框架 Anno&Viper -分布式锁是个什么鬼
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 -分布式锁是个什么鬼的更多相关文章
- .netcore 微服务快速开发框架 Anno&Viper 注册中心 (服务上线下线预警通知)
1.微服务时代,服务上线先预警通知 在微服务大行其道的今天,相信很多人都用上了微服务或者是微服务的概念也已经有了一个深刻的了解.今天我们不在这里展开阐述,今天我们要说的是微服务伴侣预警通知. 2.注册 ...
- Anno&Viper -分布式锁服务端怎么实现
1.Anno简介 Anno是一个微服务框架引擎.入门简单.安全.稳定.高可用.全平台可监控.依赖第三方框架少.底层通讯RPC(Remote Procedure Call)采用稳定可靠经过无数成功项目验 ...
- 不死的小强 .net core 微服务 快速开发框架 Viper 限流
1.Viper是什么? Viper 是.NET平台下的Anno微服务框架的一个示例项目.入门简单.安全.稳定.高可用.全平台可监控.底层通讯可以随意切换thrift grpc. 自带服务发现.调用链追 ...
- net core 微服务 快速开发框架 Viper 初体验2020-10-17
1.Viper是什么? Viper 是.NET平台下的Anno微服务框架的一个示例项目.入门简单.安全.稳定.高可用.全平台可监控.底层通讯可以随意切换thrift grpc. 自带服务发现.调用链追 ...
- 基于SpringBoot-Dubbo的微服务快速开发框架
简介: 基于Dubbo的分布式/微服务基础框架,为前端提供脚手架开发服务,结合前一篇--Web AP快速开发基础框架,可快速上手基于Dubbo的分布式服务开发,项目代码: https://github ...
- net core 微服务 快速开发框架
dymDemo github 地址:https://github.com/duyanming/dymDemo dym 分布式开发框架 Demo 熔断 限流 事件总线(包括基于内存的.rabbitmq的 ...
- 一个轻量级的.Net Core微服务快速开发的轮子
前言 Adnc是一个轻量级的.Net Core微服务快速开发框架,同时也可以应用于单体架构系统的开发.框架基于JWT认证授权.集成了一系列微服务配套组件,代码简洁.易上手.学习成本低.开箱即用 ...
- .NETCore微服务探寻(三) - 分布式日志
前言 一直以来对于.NETCore微服务相关的技术栈都处于一个浅尝辄止的了解阶段,在现实工作中也对于微服务也一直没有使用的业务环境,所以一直也没有整合过一个完整的基于.NETCore技术栈的微服务项目 ...
- (1)学习笔记 ) ASP.NET CORE微服务 Micro-Service ---- 什么是微服务架构,.netCore微服务选型
开发工具:VS2017 .Net Core 2.1 什么是微服务?单体结构: 缺点: 1)只能采用同一种技术,很难用不同的语言或者语言不同版本开发不同模块: 2)系统耦合性强,一旦其中一个模块有问题, ...
随机推荐
- 一万字详解 Redis Cluster Gossip 协议
Redis Cluster Gossip 协议 大家好,我是历小冰,今天来讲一下 Reids Cluster 的 Gossip 协议和集群操作,文章的思维导图如下所示. 集群模式和 Gossip 简介 ...
- 第8.13节 Python类中内置方法__repr__详解
当我们在交互环境下输入对象时会直接显示对象的信息,交互环境下输入print(对象)或代码中print(对象)也会输出对象的信息,这些输出信息与两个内置方法:__str__方法和__repr__方法有关 ...
- 转:【Python3网络爬虫开发实战】 requests基本用法
1. 准备工作 在开始之前,请确保已经正确安装好了requests库.如果没有安装,可以参考1.2.1节安装. 2. 实例引入 urllib库中的urlopen()方法实际上是以GET方式请求网页,而 ...
- 转:HTTP协议简介与在python中的使用详解
1. 使用谷歌/火狐浏览器分析 在Web应用中,服务器把网页传给浏览器,实际上就是把网页的HTML代码发送给浏览器,让浏览器显示出来.而浏览器和服务器之间的传输协议是HTTP,所以: HTML是一种用 ...
- PyQt(Python+Qt)学习随笔:QTableWidget的currentItem、rowCount、columnCount等部件状态属性访问方法
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 老猿将QTableWidget表格部件中反映部件当前情况的一些方法归类为部件状态访问方法,包括部件的 ...
- Get请求Test
一.新建测试套 作为管理接口,可按功能分类,也可按业务逻辑分类,根目录下最多一级子目录.运行接口时,可按测试套为单位,整体运行. 二.选择请求类型,输入接口地址 根据接口文档中提供的接口请求类型及地址 ...
- 攻防世界 web进阶区 lottery
首先进入题目的页面. 按其要求登录.然后看到以下界面. 御剑扫描目录,发现了robots.txt (robots协议) ,进入查看 进入.git/目录,用神器 GitHack 下载文件. 然后查看源码 ...
- Python运算符可不只有加减乘除
数学里面的加减乘除,就是运算符,但是 Python 的运算符更多样,更复杂,分为算术运算符.比较运算符.赋值运算符.位运算符.逻辑运算符.成员运算符.身份运算符.为了更直观的看到运算符的使用,本文采用 ...
- jQuery插件的2种类型
1.封装方法插件 封装方法插件在本质上来说,是一个对象级别的插件,这类插件首先通过jQuery选择器获取对象,并为对象添加方法,然后,将方法进行打包,封闭成一个插件,这种类型的插件编写简单,极易调用 ...
- Angular学习知识点记录
问:版本直接跳转到Angular4? 答:为了遵循严格的版本策略.在angular2.x的时候,angular route的版本已经是版本3了.因此为了版本统一,angular直接从2跳到了4,.参考 ...