PasteCluster组件介绍(一款让你的.Net服务快速支持集群部署的中间件)

前言

PasteCluster是由.NET6.0编写的集群中间件,先已开源:
PasteCluster.Gitee
在实际开发中,如果一个服务(比如api)是否支持集群部署,其实是由开发决定的!
举个栗子
我们知道缓存,可以分几种方式,最简单的就是应用缓存,也就是我们开发中使用的变量,比如全局变量,或者使用外部程序缓存比如redis,也可以使用数据库作为缓存等!
图形验证码很熟悉吧,第一步是缓存下这个客户的code是多少,然后把Image显示给客户,让客户输入,客户输入后调用注册或者其他Action进行提交,这个时候就要校验用户提交的code是否和自己存储的一致!如果你的程序使用的是程序缓存,那么这个程序就不能集群部署了!(有人会说我使用Nginx的cookie锁定,这里不严格讨论这个事情哈!)

使用案例一则

拿PasteSpider来说,PasteSpider支持集群部署,支持一拖多服务器,那么问题就来了,如果集群部署,哪些服务器由哪个PasteSpider进行管理,这就需要有一个集群管理模式
1.Master是谁,是否要遵循他们说得单数模式!(我觉得单数模式是很奇怪的设定,类似无限套娃的假设模式了)
2.哪些服务器由哪个PasteSpider(这里作为节点)管理
3.一些公共任务的执行,比如小时报表的统计(如果每个节点都执行这个任务,要么有并发的问题,要么有数据切点的问题)
引入PasteCluster后,这些问题将被综合处理,PasteSpider只要处理自己的业务代码,集群里面的选举啥的由PasteCluster进行处理!

使用案例二则

由这么一个项目需求,需要统计在线人数
使用node作为websocket的服务端,支持集群部署
一个node中可能有多个站点的用户
需求是实时知道某一个站点多少客户
1.客服客户端每秒去遍历所有的node,查询各站点的在线链接数,这个虽然可以实现需求,但是会造成极大的浪费,如果客服客户端多了会造成严重的数据浪费!
2.设定一个专门的node(na)作为master,其他的Node在链接数有变更的时候,告知这个node(na),那么问题来了,如果这个na挂了,那么会造成这个统计的中断,再者客服客户端要多一个链接到这个node(na),相比于1,明显的效率提升很多!
3.可能有人说,借助于redis的hashset的功能,++或者–数据,同样的需要一个主体去读取这个数据,然后群发给在线客服从而更新在线人数!这么执行的结果就是每个连接的变动,都需要读取hashset的列表,然后计算出结果,推送给所有的在线客服!(优秀)
4.或者我们可以换一个思想实现,node中选举一个master出来,其他节点的在线链接数变更后,把对应的数据推送给master,由master在程序内缓存中计算出站点在线人数信息,然后推送给所有客服!当这个master挂了后,由系统机制再次选举出一个master来负责这个事情!
以上的方案中,1或者2其实是不合理的,3和4,如果可以的话3还是很好的,4是在不借助外部的情况下实现的,3、4都有一个问题,那就是数据的重置!比如某一个节点引发了异常,然后重启了,那么他的数据就有一个断层了,不得不引发一个问题,上载数据的时候 是上载++ – 还是上载当前这个节点的各个站点的当前链接数!

如何使用

组件适用

1.需要集群部署的服务,需要有主从的集群服务
2.如果是定时的任务,建议使用PasteTask任务调度器实现
3.组件适用于.net6.0以上的框架
4.集群对外的消息使用Channel队列发出

引入组件

1.先引入IHttpClientFactory,示例:context.Services.AddHttpClient();
2.添加对组件的应用 示例:<PackageReference Include="PasteCluster" Version="1.0.0" />
3.使用单例注入,示例:context.Services.AddSingleton<PasteClusterHandler>();
4.配置配置文件,示例:context.Services.Configure<PasteSloveConfig>(Configuration.GetSection("ClusterConfig"));
  "ClusterConfig": {"SloveToken": "zxcvfr43dr56hgt5",//集群密钥,可自定义,防止其他集群乱入!"ClusterHost": "",//已有的节点地址链路,示例http://192.110.0.3:80;http://192.110.0.7:80"CurrentHost": ""//当前节点的访问地址是多少 示例http://192.110.0.6:80}
以上是基础配置,需要自定义更多的请查阅PasteSloveConfig的属性5.如果使用了Route路由,注意本组件需要/api/cluster/的路由转发配置

开始使用

1.初始化集群组件,写入必要的信息,比如集群中还有谁,自己的HOST是多少
2.定义一个HostedService用于接收集群产生的事件
示例代码:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using PasteCluster;
using TestCluster.redismodel;namespace TestCluster
{/// <summary>/// 系统初始化/// </summary>public class StartHostedService : IHostedService{private readonly IServiceProvider _serviceProvider;private PasteClusterHandler _cluster_handler;private IAppCache _appCache;private ILogger<StartHostedService> _logger;/// <summary>/// /// </summary>/// <param name="serviceProvider"></param>/// <param name="pasteClusterHandler"></param>/// <param name="appCache"></param>/// <param name="logger"></param>public StartHostedService(IServiceProvider serviceProvider, PasteClusterHandler pasteClusterHandler, IAppCache appCache, ILogger<StartHostedService> logger){_serviceProvider = serviceProvider;_cluster_handler = pasteClusterHandler;_appCache = appCache;_logger = logger;}private const string node_list_cache_key = "cache:last:nodes";//private System.Timers.Timer _timer;/// <summary>/// /// </summary>/// <param name="cancellationToken"></param>/// <returns></returns>/// <exception cref="System.NotImplementedException"></exception>public Task StartAsync(CancellationToken cancellationToken){//可以从他处读取集群节点列表,然后把列表写入到系统中var reads = _appCache.Get<List<PasteNodeModel>>(node_list_cache_key);if (reads != null && reads.Count > 0){foreach (var _node in reads){_cluster_handler.AddNodeToList(_node).Wait();//await _cluster_handler.AddNodeToList(_node);}}//如果已知当前节点的Host(这里示例默认为80端口)信息,可以用下方的函数写入,也可以在启动的时候写入配置中// -e ClusterConfig:CurrentHost="http://192.168.1.100"//如果使用PasteSpider部署,则是-e ClusterConfig:CurrentHost="http://{{App.ProAddress}}"//_cluster_handler.Register("http://192.168.1.100",0,0);//启动集群中的当前节点(在这之前必须要确认当前节点的host是多少)_cluster_handler.StartCluster();//读取集群产生的数据,比如其他节点发送的数据等,这里一般是业务相关的消息ReadClusterChannel();//_timer = new System.Timers.Timer();//hit_index = new Random().Next(1,100);//_timer.Interval = 1000;//_timer.AutoReset = true;//_timer.Elapsed += _timer_Elapsed;//_timer.Start();return Task.CompletedTask;}//private int hit_index = 5;//测试产生数据进行交互//private void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)//{//    try//    {//        hit_index--;//        if (hit_index == 0)//        {//            _cluster_handler.PushMsgToNode($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");//            hit_index = new Random().Next(1, 20);//        }//    }//    catch (Exception exl)//    {//        _logger.LogException(exl);//    }//}/// <summary>/// 处理集群产生的数据/// </summary>private async void ReadClusterChannel(){try{var _info = await _cluster_handler.ChannelCluster.Reader.ReadAsync();if (_info != null && _info != default){_logger.LogInformation("ClusterChannel.Message:" + Newtonsoft.Json.JsonConvert.SerializeObject(_info));if (_info.msg_type == 1){if (_cluster_handler.CurrentIsMaster){//当前节点确定选举为Master 可以执行保存等//var _nodes = _cluster_handler.Nodes();//if (_nodes != null && _nodes.Length > 0)//{//    await _appCache.SetAsync<List<PasteNodeModel>>(node_list_cache_key, _nodes.ToList());//}}}else{//业务代码处理}}}catch (Exception exl){_logger.LogException(exl);await Task.Delay(1000);}finally{ReadClusterChannel();}}/// <summary>/// /// </summary>/// <param name="cancellationToken"></param>/// <returns></returns>/// <exception cref="System.NotImplementedException"></exception>public Task StopAsync(CancellationToken cancellationToken){_cluster_handler.Dispose();return Task.CompletedTask;}}
}
3.在入口函数中启动这个HostedService
``context.Services.AddHostedService<StartHostedService>();
``

相关问答

1.如何知道当前运行情况
curl http://xxxx.xxxx.xxxx.xxxx/api/cluster/status
2.获取所有节点信息
curl http://xxxx.xxxx.xxxx.xxxx/api/cluster/nodes
3.手动注入当前节点IP信息
curl http://xxxx.xxxx.xxxx.xxxx/api/cluster/joinin?host=http://192.168.1.5
4.如何查找当前节点?
有一种模式,就是知道所有集群的IP,需要找到A是A,那么有前提
a.先要把节点的信息写入到组件,所有的节点
b.给当前节点设定一个code,可以使用SetNodeCode
c.后者使用环境信息 -e ClusterConfig:CurrentCode="xxxxxuuuu323423"
d.StartCluster()后,组件会遍历节点,查找哪个节点是自己!主要他们的链接要能通!
5.如何防止多Master的情况出现
a.在每次交互的时候,会附带当前节点的信息,比如master是谁,有多少各节点等,通过这个信息进行判断各自节点的信息是否一致,不一致的时候触发信息同步!
b.master冲突的时候,会检查哪一个节点的选举时间更早,更早的为主,时间采用时间戳ms模式,如果时间戳一致,则再对比对应的Id信息
c.节点数据交互的时候,会进行master和count的消息确定
6.消息完整性?
a.消息分成2部分,一部分是组件内部消息,另一部分是涉及业务的部分
b.内部消息,其实在配置的时间周期内会重新发送重新检查,以便维护集群节点的正确性
c.业务消息,一般是节点发送消息给master,在发送失败的时候,会压入队列,等待选举完成后再解压队列发送,这里有疑问的是,业务消息是否也有可以丢弃的消息,比如如下场景:x.已知有N个node节点,作为在线客服的websocket的服务端,内部链接又使用site分隔用户xx.如果要获得某一个站点site有多少人在线,要么遍历所有的node节点,然后统计数据,要么所有节点有信息的时候告知某一个点,很显然在这个需求中,各node节点有在线数变更的时候主动通知是最合适的xxx.比如node1告知node1:site1:30,node2告知node2:site1:25 信息归总到master中,master中本地缓存这个数据,当有变动的时候,推送给所有客服节点即可!
xxxx.这里要处理的就是,某一个节点宕机的情况,比如node5不可用了,如何告知master他掉了!

逻辑介绍

1.Master的选举逻辑a.当前组件集群支持从1到N,这个数量理论上不是无上限的,要基于配置文件中的最长交互时间决定b.当当前没有Master的时候,会从节点队列中问询谁是master,被问询的如果也没有master信息,则被问询方直接成为master,并进入master的选举环节c.节点交互会重置最后交互时间,主要在于master和clusterd.组件会定期检查这个交互时间是否过期,如果过期了,会尝试健康检查,如果不通,则进入选举模式
2.选举原则a.谁先启动谁为主b.谁被告知消息不符,谁放弃,进行master查找

写在最后

1.当前组件的代码还没有经过严格测试,我估计还有问题的地方在于
a.时效性的问题,虽然可以修改检查的间隔时间,但是这个时间也是有间隙的
b.选举间隔,产生太多消息的话?消息重复的话!压缩的消息是否对业务有影响
c.如果同时多个节点掉线,那么这个选举的时间会更长
d.当前集群模式将在后续更新到PasteSpider的集群策略中,替换到目前的版本!

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

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

相关文章

tkinter菜单栏

tkinter菜单栏 菜单栏效果代码 菜单栏 在 Tkinter 中&#xff0c;Menu 组件用于创建菜单栏、下拉菜单和上下文菜单&#xff0c;是构建图形用户界面&#xff08;GUI&#xff09;应用程序的常见需求。 效果 代码 import tkinter as tk from tkinter import messagebox# 创建主…

DAMA学习笔记(一)-数据管理

1.引言 数据管理(Data Management) 是为了 交付、 控制、 保护 并 提升 数据和信息资产的 价值 , 在其整个生命周期中制订 计划、 制度、 规程和实践 活动, 并 执行 和 监督 的过程。 数据管理专业人员(Data Management Professional) 是指 从事数据管理各方面的工作…

MySQL与PostgreSQL关键对比三(索引类型)

目录 索引类型 B-tree 索引 Hash 索引 Full-text 索引 GiST 索引 GIN 索引 BRIN 索引 索引创建示例 MySQL PostgreSQL 结论 以下SQL语句的执行如果需要开发工具支持&#xff0c;可以尝试使用SQLynx或Navicat来执行。 MySQL和PostgreSQL在索引方面有许多相似之处&am…

【C#线程设计】2:backgroundWorker

实现&#xff1a; &#xff08;1&#xff09;.控件&#xff1a;group Box&#xff0c;text Box&#xff0c;check Box&#xff0c;label&#xff0c;botton&#xff0c;richtextbox 控件拉取见&#xff1a;https://blog.csdn.net/m0_74749240/article/details/139409510?spm1…

mingw如何制作动态库附python调用

1.mingw和msvc g -fpic HelloWorld.cpp -shared -o test.dllg -L . -ltest .\test.cpp 注意-L后面的.挨不挨着都行&#xff0c;-l不需要-ltest.dll&#xff0c;只需要-ltest 2.dll.cpp extern "C" {__declspec(dllexport) int __stdcall add(int a, int b) {return…

吴恩达2022机器学习专项课程C2W3:2.25 理解方差和偏差(诊断方差偏差正则化偏差方案)

目录 引言名词替代影响模型偏差和方差的因素1.多项式阶数2.正则化参数 判断是否有高偏差或高方差1.方法一&#xff1a;建立性能基准水平2.方法二&#xff1a;建立学习曲线 总结 引言 机器学习系统开发的典型流程是从一个想法开始&#xff0c;然后训练模型。初次训练的结果通常…

C语言最终讲:预处理详解

C语言最终讲&#xff1a;预处理详解 1.预定义符号2.#define定义常量3.#define定义宏4.带有副作用的宏参数5.宏替换的规则6.宏和函数的对比6.1宏的优势6.1.1\符号 6.2宏的劣势 7.#和##7.1#运算符7.2##运算符 8.命名约定9.#undef10.命令行定义11.条件编译12.头文件的包含12.1本地…

13. UDP协议与RTP协议

UDP协议 UDP协议比较简单&#xff1a; UDP的长度是固定的&#xff0c;用总长度-UDP长度就是数据长度。 UDP是不保证他的有序性和可靠性的。对于音频和视频是这样是比较好的&#xff0c;因为这段丢了&#xff0c;我们可以从下一段在开始解码。 RTP RTP 协议概述 RTP&#x…

【MySQL】(基础篇六) —— 过滤数据

过滤数据 本文将讲授如何使用SELECT语句的WHERE子句指定搜索条件。 WHERE子句 数据库表一般包含大量的数据&#xff0c;很少需要检索表中所有行。通常只会根据特定操作或需要提取表数据的子集。只检索所需数据需要指定搜索条件&#xff08;search criteria&#xff09;&…

独孤思维:做副业,万物皆可成为素材

01 分享一个独孤日更的素材来源。 很多小伙伴&#xff0c;刚开始写自媒体&#xff0c;都喜欢一本正经的阅读书籍&#xff0c;文章。 把素材来源&#xff0c;灵感来源&#xff0c;全部押注在这个地方。 其实万物皆可成为素材。 比如昨天早上&#xff0c;独孤参加公司的会议…

代码随想录算法训练营第36期DAY56

DAY56 套磁很顺利&#xff0c;发现又有书读了&#xff01; 300最长递增子序列 朴素法&#xff0c;这个好想&#xff0c;但是不对&#xff0c;比如 0 1 0 3 2 3 我的算法会找出0 1 3作为答案&#xff0c;而不是0 1 2 3 可以看出&#xff0c;后面的状态依赖于前面的状态&am…

zero shot,few shot以及无监督学习之间的关系是什么

Zero-shot learning、few-shot learning和无监督学习都是机器学习中的方法&#xff0c;它们共同的特点是在有限或没有标签数据的情况下进行学习。下面是这三种方法之间的关系和区别&#xff1a; Zero-shot Learning (零样本学习)&#xff1a; 零样本学习是在模型训练过程中完全…

中介子方程十

X$XFX$XEXyXαXiX$XαXiXrXkXtXyX$XpX$XyXtXkXrXiXαX$XiXαXyXEX$XFX$XEXyXαXiX$XαXiXrXkXtXyX$XpX$XyXtXkXrXiXαX$XiXαXyXEX$XαXηXtXαX$XWXyX$XyXWX$XpXαXqXηX$XeXαXhX$XdX$XpX$XdX$XyXeXαX$XEXyXαXiX$XαXiXrXkXtXyX$XpX$XyXtXkXrXiXαX$XiXαXyXEX$XαXeXyX$Xd…

Facebook革新:数字社交的下一个阶段

在数字化时代&#xff0c;社交网络已经成为人们生活中不可或缺的一部分。作为全球最大的社交网络平台之一&#xff0c;Facebook一直在不断创新&#xff0c;引领着数字社交的发展。然而&#xff0c;随着科技的不断进步和社交需求的变化&#xff0c;Facebook正在走向一个新的阶段…

Gitte的使用(Windows/Linux)

Gitte的使用&#xff08;Windows/Linux&#xff09; 一、Windows上使用Gitte1.下载程序2.在Gitte上创建远程仓库3.连接远程仓库4.推送文件到远程仓库 二、Linux上使用Gitte1.第一次从仓库上传1.1生成公钥1.2配置SSH公钥1.3新建一个仓库1.4配置用户名和邮箱在Linux中1.5创建仓库…

python字典应用

""" 字典应用 字典中保存了股票信息&#xff0c;完成下面的操作 1.找出股票价格大于100元的股票并创建一个新的字典 2、找出价格最高和最低的股票对应的股票代码 3.按照股票价格从高到低给股票代码排序 """stocks {AAPL: 191.88,G00G: 1186.96,…

强烈推荐 Setapp 上的 Mac 优质软件

Setapp 一款专为 macOS 设计的软件订阅平台&#xff0c;目前提供高达 240 款精心筛选的高品质应用程序&#xff0c;只需每月 9.9 美元的订阅费&#xff0c;即可畅享所有正版软件的使用权。让使用者无忧享受正版软件的稳定性和安全性&#xff0c;彻底告别盗版软件可能引发的风险…

Linux学习问题

遇到的第一个问题&#xff0c;FinalShell连接Centos7后&#xff0c;就连不上网&#xff0c;Centos7联网后就连不上FinalShell 解决方法&#xff0c;虚拟网卡上的ip地址不能和虚拟机ip地址一样 从这得到的解决方法

【C++11】常见的c++11新特性(一)

文章目录 1. C11 简介2. 常见的c11特性3.统一的列表初始化3.1initializer_list 4. decltype与auto4.1decltype与auto的区别 5.nullptr6.右值引用和移动语义6.1左值和右值6.1.1左值的特点6.1.2右值的特点6.1.3右值的进一步分类 6.2左值引用和右值引用以及区别6.2.1左值引用6.2.2…

ELK组件

资源列表 操作系统 IP 主机名 Centos7 192.168.10.51 node1 Centos7 192.168.10.52 node2 部署ELK日志分析系统 时间同步 chronyc sources -v 添加hosts解析 cat >> /etc/hosts << EOF 192.168.10.51 node1 192.168.10.52 node2 EOF 部署Elasticsea…