分布式系统搭建:服务发现揭秘

CAP理论

加州大学终身教授与著名计算机科学家Eric Allen Brewer90年代末提出了CAP理论,理论断言任一个基于网络的分布式系统,最多只能满足“数据一致性”、“可用性”、“分区容错性”三要素中的两个要素。

该理论后被MIT证明可行,故架构师无需将精力浪费在如何设计能满足三者的完美分布式系统,而是应该进行取舍。

 

CAP理论也即被捧为“分布式系统设计”的重要评分标准,其包含下述三项定义:

 

  • Consistency(一致性):集群中所有节点在同一时刻可见同样的值。

  • Availability(可用性):健康的节点在限时内,可返回可靠的结果。

  • Partition tolerance(分区容错性):集群中某些节点失联后,集群仍可继续服务。

 

那为什么一个系统只能同时满足三要素中的两个要素呢?我们来看看下面例子:

 

1.首先使分布式系统满足“分区容错性”要素:

当上海、台北服务器共用数据存储时,上海数据中心存储的宕机将造成台北服务器也不可用,拓扑图如下。


 

如何来满足分区容错性:我们可在各数据中心分别建存储机制,在各数据中心存储进行写操作的同时,触发存储同步,保障数据中心间存储数据同步。

故当任一数据中心存储宕机,也不会造成其它数据中心的存储读写操作,如下图所示:


 

2.满足“分区容错性”的前提下,“一致性”,“可用性”两者只可选其一假定当前两地存储中的数据为“版本1”,此时上海与台北数据中心网络中断,存储间无法同步。然后上海服务器将数据版本更新为“版本2”,由于同步受阻,台北数据中心仍保存数据版本“版本1”,如下图所示:

 


“台北服务器向台北分区存储进行查询”这一动作在CAP理论模型下只能满足下述情况之一

 

CP)保障“一致性”,放弃“可用性”

等待网络恢复正常,上海存储将“版本2”同步至台北存储,台北存储将满足“一致性”的数据“版本2”返回给服务器。

由于网络恢复时间的不确定性,请求可能会超时,违反“可用性”限时的条件。

AP)保障“可用性”,放弃“一致性”

台北存储在“可用性”高响应的驱动下将过期数据“版本1”返回给服务器。

由于返回的“版本1”与最新数据“版本2”不一致,违反了“一致性”。

 

CAP理论小结:

无论CPAP还是CA,在CAP理论驱动下的系统,都以SLAService Level Agreement)为系统最终评估基准。目前SLA 59乃至69的系统,都会以AP设计为重,略微放弃一致性来换取系统的“活”。

 

目前主流的分布式系统设计理论BASEBasically Available 基本可用)(Soft State 软状态)(Eventual Consistency 最终一致性)则是对CAPAP理论的扩展,通过实现“最终一致性”来保障SLA的同时确保信息准确。

基于BASE理论设计的主要的产品则为主流NoSQL数据库:包括CassandraMongoDBRedis, CouchDB等。

 

故在AP模型稳定的情况下,SLA指标中能有几个9,与Consistency(一致性)的算法实现密切相关,下面我们来看一下“一致性算法”


一致性算法Raft

20世纪80年代开始,一致性算法的研究就没有停止过,主流的实现则依赖共享内存(Shared memory)和消息传递(Messages passing)。直至21世纪的今天,基于“消息传递”为一致性算法实现的系统占到了绝大多数。

 

微软研究院首席科学家、2013年图林奖获得者LeslieLamport1990年提出的一种基于消息传递且具有高度容错特性的一致性算法Paxos该算法的典型应用场景为分布式数据库:在一个多节点的分布式系统中,“使用一致性算法”保证每个节点执行相同的命令序列,确保每个节点的状态一致。

 

Google的分布式锁服务ChubbyApache的分布式服务框架ZooKeeper都是基于Paxos算法进行的实现。Paxos也是类似算法中最为可靠与广知的,但Paxos算法的流程复杂与实现困难导致世界级产品数量极少。

 

2013年来自Stanford大学的DiegoOngaroJohn Ousterhout发布论文“In Search of an Understandable Consensus Algorithm”,公布了的新的分布式协议研究称为Raft,它是一个为真实世界应用建立的协议,主要注重协议的落地性和可理解性。

 

时至今日,Raft的易实现性使其成为与Paxos同级别的一致性算法,在RaftGithub官网上,已发布了十多种Raft一致性算法的实现,生态圈日渐强大。详细信息可见:https://raft.github.io/

主流的服务发现框架EtcdConsul等都是基于Raft一致性算法实现的。Google开源的容器集群管理Kubernetes作为Docker生态圈中重要一员,也是基于Raft来管理一致性的。

 

Raft算法拆解后主要包含三大功能,各功能运作的完整流程也可参考Raft可视化网站,让我们通过生动的图形来了解Raft算法的秘密吧!

网址:

http://thesecretlivesofdata.com/raft/

 

1.       Leader选取

Raft服务集群中有3个角色LeaderCandidateFollowerLeader则会统一管理Follower与自己的状态机同步。

 

Raft使用心跳机制来触发选举Leader。在没有Leader的情况下在Follower默认的“选举计时器”(150毫秒到300毫秒超时)超时后,将会推举自己为Candidate,当大多数(n/2+1 )节点同意后将会升级为Leader。然后LeaderFollower间使用心跳进行状态维护,只要心跳是在“心跳计时器”超时范围内,Leader状态则可永久保持。

 

Raft算法内,只会存在一个Leader与多个Follower,集群维护单个数服务器。

 

*在极端多Follower“选举计时器”同时超时,多Candidate同时出现的情况下,则以收到其他Follower推举回应同时重置“选举计时器”的时间点来决定最终Leader

 

Leader选举的流程如下,图来自Stanford论文:


 

2.       日志复制、同步:

Leader角色负责日志同步,流程如下:

Leader收到客户端信息,则先写入本地日志文件,同时将信息发给其他Follower。当大多数Follower保存至本地成功,则回复Leader成功,Leader获取大多数Follower回复后,提交本地写入的日志,并则通知客户端收到信息。

 

Follower有丢包或者奔溃,Leader将进行重试来保障一致性。所以数据的最终提交、状态机的维护将由Leader决定。Leader会保障多数节点写入信息来进行最终提交。

 

如下图所示,Leader上最后写入的x<-4未被提交,则是由于仅有Leader1/4Follower,共2/5的节点写入此日志。而x<-5则有Leader1/2Follower,共3/5 (n/2+1)节点写入此日志,Leader发现大多数节点3/5已写入信息成功,做了最终提交。

 


 

3.       安全性:

Leader作为Raft集群的控制核心,也存在奔溃的可能。此时则集群中任意Follower可推举自己为CandidateRaft的安全性保障当Follower如没有获得当前完整Committed entries(见上图)时,则无法成为Candidate。此安全性举动保障了数据的可靠性,不会丢数据。

 

如要保障新选举的Leader不会将过期脏数据同步至Follower。安全性检查会在做数据的提交时,也检查当前Leader所要提交的数据至少有一个存储在大部分Follower上。

 

当新Leader在工作的同时,老Leader突然恢复工作。Raft的安全性保障使用Term号的方式使老Leader发出的过期Term号对所有Follower都不生效。保障了老Leader不会触发错误同步,直至降级为Follower

 

Raft一致性算法小结:

Raft通过算法实现强一致性。但是其单一Leader节点的设计在写操作量大的情况下会造成单点写瓶颈。故使用场景为读操作大于写操作的,对一致性要求高的系统。

 

服务发现框架Consul介绍

ConsulHashicorp公司使用Go语言编写的开源项目,其核心是基于RaftCAP一致性算法)与GossipBASE最终一致性算法)进行实现的。基于RaftGossipConsul集群,可保障Consul Server集群(服务端)间的数据一致性同步,Consul Server集群与集群间、Consul Agent(客户端)与Agent间的数据最终一致性同步。

 

*Gossip最终一致性算法尝试解决的问题是:在一个有界网络中,每个节点都随机地与其他节点通信,经过一番杂乱无章的通信,最终所有节点的状态都会达成一致。Gossip具有“去中心化的特点”,也天然具有分布式容错,虽然无法保证在某个时刻所有节点状态一致,但可以保证在最终所有节点一致。

 

Consul的特色非常适合融入当前互联网公司的微服务架构,可轻松覆盖多种操作系统。官方已经发布的Consul客户端支持Mac OS XFreeBSDLinuxSolarisWindows等多种操作系统,发布在这些操作系统上的Restful API都可轻松接入Consul集群。

 

Consul产品开源的同时也提供了多种语言的接入SDK,包括GoPythonPhpScalaJavaErLangRubyNode.js.NETPerl等,大大降低了开发人员的接入工时。

 

下图为Consul在多数据中心部署的架构图,单数据中心内使用Raft算法保障服务端一致性,同时使用Gossip协议进行跨数据中心(WAN Gossip)同步,与客户端间(LAN Gossip)同步。

两种一致性算法结合使用的Consul集群可保证各个节点的数据一致。


 

.NET API服务如何接入Consul服务发现框架

首先将Consul以服务端模式部署在至少3台(总台数为单数)服务器上,然后在.NET API部署服务器上安装Consul Agent模式

由于.NET API多运行于Windows服务器上,可使用nssm.exehttp://www.nssm.cc/)来进行从命令行至windows服务的包装,保障跨Windows会话的安全性。

 

服务端启动脚本,需使用-ui-dir来指定UI项目路径

Consul  agent -server -bootstrap-expect 2 -data-dir  D:\TGOP\ServiceDiscovery\ConsulData -node=TGOP-Consul-Server1 -bind=172.16.11.211  -dc=Shanghai-DC1 -client=172.16.11.211 -ui-dir=./UI

 

Agent端启动脚本仅需加入指定Consul服务端集群

Consul  agent -data-dir D:\TGOP\ServiceDiscovery\ConsulData  -node=TGOP-Consul-Agent-LucasPC -bind=127.0.0.1 -dc=Shanghai-DC1 -client=127.0.0.1  -join tgop-apistore.vipabc.com

 

Consul服务端与Agent端启动后,可通过http://consulserver:8500/ui 地址进行Consul集群健康状态管理。


 

.NET API服务发布与发现的SDK接入方法:

 

通过Nuget包管理器还原并安装Consul.NET SDK安装包,当前版本为7.0.5。使用SDK安装包中提供的ConsulClient.Agent.ServiceRegister方法进行“服务注册”,可使用的默认Agent地址为http://127.0.0.1:8500/ 核心方法如下

Task<WriteResult>  ServiceRegister(AgentServiceRegistration service, CancellationToken

 ct = null);

 

使用ConsulClient.Agent. ServiceDeregister方法进行“服务注销”

Task<WriteResult> ServiceDeregister(string serviceID, CancellationToken ct = null);

 

使用ConsulClient.Health.Service方法进行“服务发现”,将会返回符合要求的服务列表,后通过主流负载均衡算法进行最终服务筛选,完成服务发现流程。

Task<QueryResult<ServiceEntry[]>> Service(string  service, string tag, bool passingOnly, CancellationToken ct = null);

 

.NET API启动与退出时集成Consul.NET SDK相应的注册与注销方法,完成服务自注册。在.NET API需要与其他API进行通讯时,使用服务发现方法完成地址查询,后发起Restful HTTP请求完成API调用。

进行服务注册时,需通过AgentServiceRegistration.AgentServiceCheck类型将心跳HTTP的接口信息,心跳间隔信息等同时递交注册,ConsulAgent将会以配置好的间隔对服务进行心跳检查,来保障任意Agent进行“服务发现”时,获取的注册API为可用的。

 

Consul服务发现框架集成小结:

Consul集群基础设施部署完毕,相应SDK语言包成熟的基础上,用户开发的Restful API可轻松接入集群。Consul的核心架构于一致性算法的基石上,各服务节点的信息可靠性、可用性得到高保障,服务与服务之间可无障碍进行沟通,形成微服务网。

 

参考文献:

https://en.wikipedia.org/wiki/Eric_Brewer_(scientist)

https://en.wikipedia.org/wiki/CAP_theorem

http://www.julianbrowne.com/article/viewer/brewers-cap-theorem

https://en.wikipedia.org/wiki/Raft_(computer_science)

https://ramcloud.stanford.edu/wiki/download/attachments/11370504/raft.pdf

https://en.wikipedia.org/wiki/Paxos_(computer_science)

https://en.wikipedia.org/wiki/Gossip

https://raft.github.io/

http://thesecretlivesofdata.com/raft/

https://www.consul.io/docs/internals/architecture.html

https://www.nuget.org/packages/Consul

相关文章: 

  • Consul入门

  • 使用C# 和Consul进行分布式系统协调

  • Consul 服务注册与服务发现

  • 搭建consul 集群

原文地址:http://www.rcgus.com/gyys377188451/2352438.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

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

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

相关文章

SSL / TLS 协议运行机制详解

转载自 SSL / TLS 协议运行机制详解 互联网的通信安全&#xff0c;建立在SSL/TLS协议之上。 本文简要介绍SSL/TLS协议的运行机制。文章的重点是设计思想和运行过程&#xff0c;不涉及具体的实现细节。如果想了解这方面的内容&#xff0c;请参阅RFC文档。 一、作用 不使用SS…

java实现人脸识别源码【含测试效果图】——Dao层(BaseDao)

package org.dao;import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List;/*** * * 项目名称&#xff1a;test_face_photo * 类名称&#…

统计单词出现的次数并进行排

统计 统计相同单词的次数 //使用map集合进行存储 String s"Day by Day"; Map<String,Integer> mapnew HashMap<String,Integer>(); StringTokenizer tokenizernew StringTokenizer(s); int count;//记录次数 String word;//单个单词 while(tokenizer.ha…

Mybatisplus 自动生成字段 强制覆盖 null或者空字符串也覆盖

ApiModelProperty(value "证件号码&#xff0c;现在是身份证号") TableField("id_number") private String idNumber;ApiModelProperty(value "证件到期日期") TableField(value "id_card_expire_date",fill FieldFill.UPDATE) priv…

在ASP.NET Core Web API上使用Swagger提供API文档

我在开发自己的博客系统&#xff08;http://daxnet.me&#xff09;时&#xff0c;给自己的RESTful服务增加了基于Swagger的API文档功能。当设置IISExpress的默认启动路由到Swagger的API文档页面后&#xff0c;在IISExpress启动Web API站点后&#xff0c;会自动重定向到API文档页…

一文告诉你 Java RMI 和 RPC 的区别

转载自 一文告诉你 Java RMI 和 RPC 的区别 RPC 远程过程调用 RPC&#xff08;Remote Procedure Call Protocol&#xff09;远程过程调用协议&#xff0c;通过网络从远程计算机上请求调用某种服务。一次RPC调用的过程大概有10步&#xff1a; 1.执行客户端调用语句&#xff…

java实现人脸识别源码【含测试效果图】——Dao层(IBaseDaoUtil)

/*** */ package org.dao;/*** * * 项目名称&#xff1a;test_face_photo * 类名称&#xff1a;IBaseDaoUtil * 类描述&#xff1a; 共用接口 * 创建人&#xff1a;Mu Xiongxiong * 创建时间&#xff1a;2017-9-22 下午6:59:36 * 修改人&#xff1a;Mu Xiong…

stream 提取某字段_java8从list集合中取出某一属性的值的集合案例

List orderNoListlist.stream().map(Order::getOrderNo).collect(Collectors.toList()); https://blog.csdn.net/weixin_39702400/article/details/111895006 我就废话不多说了&#xff0c;大家还是直接看代码吧~ List list new ArrayList(); Order o1 new Order("1&q…

线程VS进程

什么是线程、什么是进程 在Java中要同时执行&#xff08;如果是单核&#xff0c;准确的说是交替执行&#xff09;多个任务&#xff0c;使用的是多线程&#xff0c;而要理解线程&#xff0c;我们先要了解什么是进程什么是线程。 一般的定义&#xff1a;进程是指在操作系统中正在…

Java架构师必须知道的 6 大设计原则

转载自 Java架构师必须知道的 6 大设计原则 在软件开发中&#xff0c;前人对软件系统的设计和开发总结了一些原则和模式&#xff0c; 不管用什么语言做开发&#xff0c;都将对我们系统设计和开发提供指导意义。本文主要将总结这些常见的原则&#xff0c;和具体阐述意义。 开发…

java实现人脸识别源码【含测试效果图】——Dao层(IUserDao)

/** * Title: IUserDao.java * Package org.dao * Description: TODO该方法的主要作用&#xff1a; * author A18ccms A18ccms_gmail_com * date 2017-9-22 下午8:51:34 * version V1.0 */ package org.dao;import org.entity.Users;/** * * 项目名称&#xff1a;te…

Flux --gt; Redux --gt; Redux React 入门 基础实例教程

本文的目的很简单&#xff0c;介绍Redux相关概念用法 及其在React项目中的基本使用 假设你会一些ES6、会一些React、有看过Redux相关的文章&#xff0c;这篇入门小文应该能帮助你理一下相关的知识 一般来说&#xff0c;推荐使用 ES6ReactWebpack 的开发模式&#xff0c;但Webpa…

mybatisplus 强制制空 空覆盖原来的字符串

ApiModelProperty(value "证件照片url") TableField(value "id_photo_url",fill FieldFill.UPDATE) private String idPhotoUrl; 方法一 Data EqualsAndHashCode(callSuper false) Accessors(chain true) TableName("base_party_member") A…

Callable和Future

它们俩其实挺有意思&#xff0c;在运行的时候各司其职&#xff0c;Callable产生结果&#xff0c;Future获取结果。 使用步骤如下&#xff1a; 创建 Callable 接口的实现类&#xff0c;并实现 call() 方法&#xff0c;该 call() 方法将作为线程执行体&#xff0c;并且有返回值…

java实现人脸识别源码【含测试效果图】——DaoImpl层(BaseDaoUtilImpl)

/*** */ package org.dao.impl;import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List;import org.dao.BaseDao; import org.entity.Users; import org.junit.Test;/*** * * 项目名称&#xff1a;test_BaseDao …

90 % Java 程序员被误导的一个性能优化策略

转载自 90 % Java 程序员被误导的一个性能优化策略 我们经常看到一些 Java 性能优化的书或者理念&#xff0c;说不要在循环内定义变量&#xff0c;这样会占用过多的内存影响性能&#xff0c;而要在循环外面定义。接触 Java 这么久以来&#xff0c;相信很多 Java 程序员都被这…

微软开源Visual Studio测试平台VSTest

IT之家1月21日消息 微软在MSDN博客上宣布&#xff0c;开源旗下Visual Studio测试平台VSTest。这一平台是具备高扩展性的单元测试执行框架&#xff0c;能够在不同的核心之间实现并行化&#xff0c;提供进程隔离&#xff0c;并能够整合进Visual Studio。 目前&#xff0c;VSTest能…

nacos 读取纯数字字符 出错 @value

ums: baseUrl: http://xxxx/xx/Api code: 00972315 纯数字要加单引号

java实现人脸识别源码【含测试效果图】——DaoImpl层(UserDaoImpl)

/** * Title: UserDaoImpl.java * Package org.dao.impl * Description: TODO该方法的主要作用&#xff1a; * author A18ccms A18ccms_gmail_com * date 2017-9-22 下午8:52:58 * version V1.0 */ package org.dao.impl;import org.dao.IUserDao; import org.entity.Use…

线程的状态与调度

当我们使用new关键字新建一个线程&#xff0c;这个时候线程就进入了新建状态&#xff08;New&#xff09;&#xff0c;也就是图中未启动状态&#xff1b;调用start方法启动线程&#xff0c;这个时候就进入了可运行状态&#xff0c;也就是就绪状态&#xff08;Runnable&#xff…