分布式(一致性协议)之领导人选举( DotNext.Net.Cluster 实现Raft 选举 )

分布式(一致性协议)之领导人选举( DotNext.Net.Cluster 实现Raft 选举 )

继分布式锁之后的又一高可用技术爽文之分布式领导选举 或者说 分布式一致性协议的实现

分布式选举是实现高可用的必备技术,想实现主从,就必须得有选举的策略,有主从才会有一个真正的管理端进行资源的协调分配。

首先需要明确的是一致性算法的目标是什么,主要面对的问题是在只使用单个服务器时由于发生错误导致数据丢失等事情发生。解决这个问题的思路也很简单,就是备份,集群,多个服务器,将操作重复到多个机器上就不怕单个机器出错了。但随之而来的就是,数据不一致、乱序等问题,一致性算法想要做到的是即使有结点出错,对外仍是一个完整的可以正常工作的整体。

选举算法

实现一致性协议(选举)的主要算法有两种

  1. 1. Raft

  2. 2. Paxos

相当于 Paxos 来讲, Raft协议相对来讲简单一点。但是,Raft 实现起来也不是很容易,如果有朋友试图想去实现可以参考,这个地方

地址 :https://zinglix.xyz/2020/06/25/raft/

我个人也是 简单的理解了一下。

Raft 是一个非拜占庭的一致性算法,即所有通信是正确的而非伪造的。N 个结点的情况下(N为奇数)可以最多容忍 (N−1)/2个结点故障

为啥需要单独的选举算法

我曾经试图实现一个WEB服务功能,我不能保证这个服务的高可用,我又不想用其他的现有服务,我就想让服务自己本身能支持高可用。

当时,因为自己认知的问题,并没有短时间找到一个可用的方案,不过现在有了。

要是当时有,可能就是别样风景了,不好说。

分布式选举的大致算法

简单的来讲就是找到一个领头的,假设有一个leader key,redis里,谁抢到了,谁就是leader,也是可以实现的。这种分布式锁实现的领导选举也可以适用于简单的项目中,并且,支持单个服务主机。

想用分布式选举算法,机器最少得2台以上,或者是概念上的两台。

Raft中主要有三个角色 Leader(领导人)、Follower (跟随者)和 Candidate(候选人),当某台机器成为了领导人,就会成为主要对外对接人,然后把对接的事情同步给下边的跟随者或者候选人同步信息。

因为对外只能有一个主服务,起到协调管理的作用。

这样,就会把相应的指令(日志)分配各个客户端,起到数据一致性的作用 ,这样,当领导人废了,下个人接任,还能继续起到作用。

Raft 选举的实例

我找了很多.Net 实现的Raft,很多只能说是个玩具,不能用于生产。

不过幸好,还真有生产级别的。

那就是 DotNext.Net.Cluster 和 DotNext.AspNetCore.Cluster (支持http ) 。

主要是基于 DotNext 中的组件。

DotNext.Net.Cluster 和 DotNext.AspNetCore.Cluster

  1. 1. DotNext.Net.Cluster包含集群编程模型、Raft 算法的传输无关实现、Raft 的 TCP 和 UDP 传输绑定、HyParView membersip 协议的传输无关实现,用于基于 Gossip 的消息传递

  2. 2. DotNext.AspNetCore.Cluster是基于DotNext.Net.Cluster库的 Raft 和 HyParView 算法的具体实现,用于构建 ASP.NET Core 应用程序

支持的功能列表

支持的功能列表:

  1. 1. 网络传输:TCP、UDP、HTTP 1.1、HTTP/2、HTTP/3

  2. 2. TLS 支持:TCP、HTTP 1.1、HTTP/2、HTTP/3

  3. 3. 支持日志压缩的高性能、通用Persistent Write-Ahead Log

  4. 4. 跨集群节点复制日志条目

  5. 5. 与 ASP.NET Core 框架紧密集成

  6. 6. 对 Docker/LXC/Windows 容器友好

  7. 7. 一切都是可扩展的

  • • 7.1 自定义预写日志

  • • 7.2 自定义网络传输

  • • 7.3 集群成员发现

基于 DotNext.Net.Cluster 的TCP 选举实例

其实他也是支持http的,当然,更多姿势,得大佬自己去挖掘了。

项目大致结构

e6b8b32d9afd856a99b06f3bfe0f7e2e.png

细心的小伙伴就会发现,这个是个.Net 6的项目,因为它的nuget包,只支持.Net 6的。

有需要的可以自己改改。

项目是参考源示例,改了一下,有需要的朋友直接去看官方案例

项目重点

Install-Package DotNext.Net.Cluster -Version 4.6.0

DataModifier.cs

internal sealed class DataModifier : BackgroundService
{private readonly IRaftCluster cluster;private readonly ISupplier<long> valueProvider;public DataModifier(IRaftCluster cluster, ISupplier<long> provider){this.cluster = cluster;valueProvider = provider;}protected override async Task ExecuteAsync(CancellationToken stoppingToken){while (!stoppingToken.IsCancellationRequested){await Task.Delay(1000, stoppingToken).ConfigureAwait(false);var leadershipToken = cluster.LeadershipToken;TitleInfo.Show(!leadershipToken.IsCancellationRequested);if (!leadershipToken.IsCancellationRequested){var newValue = valueProvider.Invoke() + 500L;Console.WriteLine("保存领导节点生成的值 {0}", newValue);var source = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken, leadershipToken);try{var entry = new Int64LogEntry { Content = newValue, Term = cluster.Term };await cluster.ReplicateAsync(entry, source.Token);}catch (Exception e){Console.WriteLine("未知异常 {0}", e);}finally{source?.Dispose();}}}}
}

这个应该是核心服务,会与其他客户端进行通信和具体的选举,以及日志的传输

Program.cs

class Program
{static async Task Main(string[] args){await UseTcpTransport(Path.Combine(AppContext.BaseDirectory, "raftConfig"));}static Task UseTcpTransport(string path){//获取所有配置var jsonConfiguration = new ConfigurationBuilder().SetBasePath(Environment.CurrentDirectory).AddJsonFile("appsettings.json", optional: true, reloadOnChange: true).Build();var NodeInfo = new NodeInfo();jsonConfiguration.Bind("NodeInfo", NodeInfo);Console.WriteLine($"MainNode:{NodeInfo.MainNode}");TitleInfo.Node = NodeInfo.MainNode;var configuration = new RaftCluster.TcpConfiguration(IPEndPoint.Parse(NodeInfo.MainNode)){RequestTimeout = TimeSpan.FromMilliseconds(140),LowerElectionTimeout = 150,UpperElectionTimeout = 300,TransmissionBlockSize = 4096,ColdStart = false,};//加载全部地址//线上环境自己重写服务var builder = configuration.UseInMemoryConfigurationStorage().CreateActiveConfigurationBuilder();foreach (var item in NodeInfo.Nodes){var address = IPEndPoint.Parse(item);builder.Add(ClusterMemberId.FromEndPoint(address), address);}builder.Build();TitleInfo.Show();return UseConfiguration(configuration, path);}static async Task UseConfiguration(RaftCluster.NodeConfiguration config, string? persistentStorage){var loggerFactory = new LoggerFactory();var loggerOptions = new ConsoleLoggerOptions{LogToStandardErrorThreshold = LogLevel.Warning};loggerFactory.AddProvider(new ConsoleLoggerProvider(new FakeOptionsMonitor<ConsoleLoggerOptions>(loggerOptions)));config.LoggerFactory = loggerFactory;using var cluster = new RaftCluster(config);cluster.LeaderChanged += ClusterConfigurator.LeaderChanged;var modifier = default(DataModifier?);if (!string.IsNullOrEmpty(persistentStorage)){var state = new SimplePersistentState(persistentStorage, new AppEventSource());cluster.AuditTrail = state;modifier = new DataModifier(cluster, state);}await cluster.StartAsync(CancellationToken.None);await (modifier?.StartAsync(CancellationToken.None) ?? Task.CompletedTask);//控制台等待取消using var handler = new CancelKeyPressHandler();Console.CancelKeyPress += handler.Handler;await handler.WaitAsync();Console.CancelKeyPress -= handler.Handler;//停止服务await (modifier?.StopAsync(CancellationToken.None) ?? Task.CompletedTask);await cluster.StopAsync(CancellationToken.None);}
}

总体来说,项目还是很简单的。

我把客户端的地址给配置了

appsettings.json

这个结构应该很容易理解,一个是当前端的地址,一个是所有节点的地址,当然也包含当前地址。

{"NodeInfo": {"MainNode": "127.0.0.1:6001" ,"Nodes": ["127.0.0.1:6001","127.0.0.1:6002","127.0.0.1:6003"]}
}

运行方式

我自己是把Bin目录复制三份,每份的 appsettings.json 修改下,然后,双击 RaftDemo.exe 就运行起来了。

注意

如果起用一个节点没个卵用,最少得两个节点。

运行效果

b5243350eacac998f407aaa84b9581c7.gif

总结

这个库是可以用在生产环境的,所以,还是值得研究一下下的。

代码地址

https://github.com/kesshei/RaftDemo.git

https://gitee.com/kesshei/RaftDemo.git

参考文档

https://zinglix.xyz/2020/06/25/raft/

https://github.com/dotnet/dotNext/tree/master/src/cluster

一键三连呦!,感谢大佬的支持,您的支持就是我的动力!

坚持更了大概一个月,也有几个铁粉了,会持续更,但是连续更太累了(按天更吃不消哦)。

感谢大佬的支持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/285240.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

投巧解决JavaScript split方法出现空字符的问题

直接使用split&#xff0c;前后各有一个“”值。 >> var str,a,b,c,d,e,f,; >> str.split(,);//(8) ["", "a", "b", "c", "d", "e", "f", ""]临时方法&#xff1a;split后&…

C语言试题146之反向输出一个链表

📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 题目:反向输出一个链表 2 、温馨提…

【ArcGIS Pro微课1000例】0006:ArcGIS Pro 2.5三维显示DEM数字高程模型

通过ArcGIS的学习,我们知道,ArcScene可以实现二维数据的三维显示,是将二维数据(例如DEM)进行自定义表面浮动拉伸。那么ArcGIS Pro中能不能实现DEM的三维显示呢? ArcScene三维显示结果: 目前所采用的ArcGIS Pro 2.5版本还不能直接将DEM进行三维显示,我们的做法是参照Ar…

中国古代历朝首都一览

【五帝时期】&#xff08;约公元前26世纪初—公元前2070年&#xff09; 『黄帝』有熊&#xff08;今河南郑州新郑&#xff09; 『颛顼』帝丘&#xff08;今河南濮阳&#xff09; 『帝喾』帝丘&#xff08;今河南濮阳&#xff09;、西亳&#xff08;今河南洛阳偃师西&#xff09…

程序员的自我修养:有助于提高沟通能力的7本书

直接影响工作效率的四种能力&#xff1a;沟通能力、自学能力、自我管理能力、问题解决能力。提高沟通能力&#xff0c;是程序员提高自我修养的必要条件。相信很多人跟我一样&#xff0c;性格内向&#xff0c;信仰技术&#xff0c;很少有跟人说话的愿望&#xff0c;只是想看代码…

玩转 Linux 之:磁盘分区、挂载知多少?

转载于&#xff1a;http://my.oschina.net/leejun2005/blog/290073 在做日志机扩容的时候&#xff0c;发现运维同学将一块硬盘的挂载点没有同以前的日志机保持一致&#xff0c;考虑到这会给日后的维护带来麻烦&#xff0c;于是尝试着手修改&#xff0c;在修改的同时&#xff0c…

C# NanoFramework 点灯和按键 之 ESP32

本来周末是要搞个大的&#xff0c;WIFI 和 Web网页之类的&#xff0c;奈何搞了两天&#xff0c;并与外国友人聊过后&#xff0c;才发现是固件有问题&#xff0c;晚上与大佬进行交流后才发现&#xff0c;原来ESP32S的官方固件有问题&#xff0c;搞不了。所以&#xff0c;建议买的…

【ArcGIS Pro微课1000例】0002:ArcGIS Pro 2.5二三维联动显示

ArcGIS Pro是一款全新的桌面应用程序,它改变了桌面GIS的工作方式,以满足新一代WebGIS应用模式。ArcGIS Pro采用Ribbon界面风格,给人全新的用户体验。它作为一个高级的应用程序,可以对来自本地、ArcGIS Online、或者Portal for ArcGIS的数据进行可视化、编辑、分析。同时,实…

Spring Boot 解决跨域Cors问题

后端主要代码&#xff1a; &#xff08;http://localhost:8080/ &#xff09; /*WebCorsConfig.java*/ package com.example.demo.Controller;import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsR…

C语言试题147之创建一个链表并且排序输出这个链表

📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 题目:创建一个链表并且排序输出这…

DOM节点创建(jQuery)

1DOM创建节点及节点属性 通过JavaScript可以很方便的获取DOM节点&#xff0c;从而进行一系列的DOM操作。但实际上一般开发者都习惯性的先定义好HTML结构&#xff0c;但这样就非常不灵活了。 试想下这样的情况&#xff1a;如果我们通过AJAX获取到数据之后然后才能确定结构的话&a…

PHP中刷新输出缓冲

2019独角兽企业重金招聘Python工程师标准>>> http://www.cnblogs.com/mutuan/archive/2012/03/18/2404957.html 转载于:https://my.oschina.net/wuzhencan/blog/652259

2021最新计算机二级C语言试题

一、选择题 (1) 下面叙述正确的是( C ) A. 算法的执行效率与数据的存储结构无关 B. 算法的空间复杂度是指算法程序中指令(或语句)的条数 C. 算法的有穷性是指算法必须能在执行有限个步骤之后终止 D. 以上三种描述都不对 (2) 以下数据结构中不属于线性数据结构的是( C ) A…

[webpack3.8.1]Guides-4-Output Management(输出管理)

Output Management This guide extends on code examples found in the Asset Management guide.这个指南将在上一个指南的基础上对示例代码进行扩展。 So far weve manually included all our assets in our index.html file, but as your application grows and once you sta…

有条件地 [JsonIgnore]

前言通常&#xff0c;在进行 JSON 序列化或反序列化时&#xff0c;如果要忽略某个属性&#xff0c;我们会使用 [JsonIgnore] 特性&#xff1a;public class User {public int Id { get; set; }[JsonIgnore]public string Name { get; set; } }var user new User { Id 1, Name…

C语言试题145之创建一个链表

📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 题目:创建一个链表 2 、温馨提示 …

[转]IntelliJ IDEA 2019.3正式发布,给我们带来哪些新特性?

每篇一句 工欲善其事必先利其器 ——《论语卫灵公》 前言 千呼万唤始出来。自从JetBrains在今年7月24日发布了IDEA 2019.2版本后&#xff0c;从9月份开始我便一直在关注此版本正式版的发布。JetBrains公司在9月中旬就对外公布了下一个主要版本 2019.3的Roadmap&#xff0c;而且…

Git中的日常使用 码云

http://git.mydoc.io/?t83143转载于:https://www.cnblogs.com/yangyuqiu/p/6164822.html

【谭浩强版】C语言程序设计(第三版)课后习题完整答案附源码--高等教育出版社

文章目录 第一章 语言程序设计的概念第二章 基本数据类型第三章 C语言程序的流程控制第四章 模块化程序设计第五章 数组第六章 指针第一章 语言程序设计的概念 1.1 请编写一个程序, 显示以下两行文字。 #include <stdio.h> main() {printf("I am a student.\n&qu…

php判断是否为json格式的方法

http://www.poluoluo.com/jzxy/201403/265005.html 首先要记住json_encode返回的是字符串, 而json_decode返回的是对象 判断数据不是JSON格式: .代码如下:function is_not_json($str){ return is_null(json_decode($str));}判断数据是合法的json数据: (PHP版本大于5.3) .代码如…