分布式【凤凰架构】

服务注册与发现

服务注册:(如调用 API、产生事件消息、在 ZooKeeper/Etcd 的指定位置记录、存入数据库,等等)将自己的坐标信息通知到服务注册中心,这个过程可能由应用程序本身来完成,称为自注册模式,譬如 Spring Cloud 的@EnableEurekaClient 注解;也可能由容器编排框架或第三方注册工具来完成,称为第三方注册模式,譬如 Kubernetes 和 Registrator。

  • 服务的维护(Service Maintaining):尽管服务发现框架通常都有提供下线机制,但并没有什么办法保证每次服务都能优雅地下线(Graceful Shutdown)而不是由于宕机、断网等原因突然失联。所以服务发现框架必须要自己去保证所维护的服务列表的正确性,以避免告知消费者服务的坐标后,得到的服务却不能使用的尴尬情况。现在的服务发现框架,往往都能支持多种协议(HTTP、TCP 等)、多种方式(长连接、心跳、探针、进程状态等)去监控服务是否健康存活,将不健康的服务自动从服务注册表中剔除。
  • 服务的发现(Service Discovery):这里的发现是特指狭义上消费者从服务发现框架中,把一个符号(譬如 Eureka 中的 ServiceID、Nacos 中的服务名、或者通用的 FQDN)转换为服务实际坐标的过程,这个过程现在一般是通过 HTTP API 请求或者通过 DNS Lookup 操作来完成,也还有一些相对少用的方式,譬如 Kubernetes 也支持注入环境变量来做服务发现。

服务注册中心都是以集群的方式进行部署的,通常使用三个或者五个节点(通常最多七个,一般也不会更多了,否则日志复制的开销太高)来保证高可用。注册中心这有CAP矛盾,副本间的CP和AP

服务注册中心Eureka

Eureka 的选择是优先保证高可用性,相对牺牲系统中服务状态的一致性。Eureka 的各个节点间采用异步复制来交换服务注册信息,当有新服务注册进来时,并不需要等待信息在其他节点复制完成,而是马上在该服务发现节点宣告服务可见,只是不保证在其他节点上多长时间后才会可见。同时,当有旧的服务发生变动,譬如下线或者断网,只会由超时机制来控制何时从哪一个服务注册表中移除,变动信息不会实时的同步给所有服务端与客户端。这样的设计使得不论是 Eureka 的服务端还是客户端,都能够持有自己的服务注册表缓存,并以 TTL(Time to Live)机制来进行更新,哪怕服务注册中心完全崩溃,客户端在仍然可以维持最低限度的可用。Eureka 的服务发现模型对节点关系相对固定,服务一般不会频繁上下线的系统是很合适的,以较小的同步代价换取了最高的可用性;Eureka 能够选择这种模型的底气在于万一客户端拿到了已经发生变动的错误地址,也能够通过 Ribbon 和 Hystrix 模块配合来兜底,实现故障转移(Failover)或者快速失败(Failfast)。

Consul

Consul 的选择是优先保证高可靠性,相对牺牲系统服务发现的可用性。Consul 采用Raft 算法,要求多数派节点写入成功后服务的注册或变动才算完成,严格地保证了在集群外部读取到的服务发现结果必定是一致的;同时采用 Gossip 协议,支持多数据中心之间更大规模的服务同步。 没有 Netflix OSS 那样有着全家桶式的微服务组件兜底

CP还是AP 取决于 更不能容忍 分区不一致还是不可用

如果是基于 Etcd/zookeeper 实现的,那自然是 CP 的,如果是基于内存异步复制的方案实现的,那就是 AP 的(仅针对 DNS 服务器本身,不考虑本地 DNS 缓存的 TTL 刷新) Redis AP的

专门用于服务发现的框架和工具,这类的代表是 Eureka、Consul 和 Nacos。这一类框架中,你可以自己决定是 CP 还是 AP 的问题,譬如 CP 的 Consul、AP 的 Eureka,还有同时支持 CP 和 AP 的 Nacos

网络IO

每一次网络访问,从远程主机返回的数据会先存放到操作系统内核的缓冲区中,然后内核的缓冲区复制到应用程序的地址空间,所以当发生一次网络请求发生后,将会按顺序经历“等待数据从远程主机到达缓冲区”和“将数据从内核缓冲区拷贝到应用程序地址空间”两个阶段,根据实现这两个阶段的不同方法,人们把网络 I/O 模型总结为两类、五种模型

异步 I/O 中数据到达缓冲区后,不需要由调用进程主动进行从缓冲区复制数据的操作,而是复制完成后由操作系统向线程发送信号,所以它一定是非阻塞的。

同步 I/O(Synchronous I/O):

  1. 阻塞 I/O(Blocking I/O):你去到饭堂,发现饭还没做好,你也干不了别的,只能打个瞌睡(线程休眠),直到饭做好。阻塞 I/O 是最直观的 I/O 模型,逻辑清晰,也比较节省 CPU 资源,但缺点就是线程休眠所带来的上下文切换,这是一种需要切换到内核态的重负载操作,不应当频繁进行。

2. 非阻塞 I/O(Non-Blocking I/O):每隔 3 分钟轮询直到饭做好。白白浪费了 CPU 资源,所以目前并不常用

3. 多路复用 I/O(Multiplexing I/O):多路复用 I/O 本质上是阻塞 I/O 的一种,但是它的好处是可以在同一条阻塞线程上处理多个不同端口的监听类比的情景是你名字叫雷锋,代表整个宿舍去饭堂打饭,去到饭堂,发现饭还没做好,还是继续打瞌睡,但哪个舍友的饭好了,你就马上把那份饭送回去,然后继续打着瞌睡哼着歌等待其他的饭做好。多路复用 I/O 是目前的高并发网络应用的主流,它下面还可以细分 select、epoll、kqueue 等不同实现。

4.信号驱动 I/O(Signal-Driven I/O):你去到饭堂,发现饭还没做好,但你跟厨师熟,跟他说饭做好了叫你,然后回去该干嘛干嘛,等收到厨师通知后,你把饭从饭堂拿回宿舍。这里厨师的通知就是那个“信号”,信号驱动 I/O 与异步 I/O 的区别是“从缓冲区获取数据”这个步骤的处理,前者收到的通知是可以开始进行复制操作了,即要你自己从饭堂拿回宿舍,在复制完成之前线程处于阻塞状态,所以它仍属于同步 I/O 操作,而后者收到的通知是复制操作已经完成,即外卖小哥已经把饭送到了。

服务容错

故障转移(Failover):高可用的服务集群中,多数的服务——尤其是那些经常被其他服务所依赖的关键路径上的服务,均会部署有多个副本。这些副本可能部署在不同的节点(避免节点宕机)、不同的网络交换机(避免网络分区)甚至是不同的可用区(避免整个地区发生灾害或电力、骨干网故障)中。故障转移是指如果调用的服务器出现故障,系统不会立即向调用者返回失败结果,而是自动切换到其他服务副本,尝试其他副本能否返回成功调用的结果,从而保证了整体的高可用性。故障转移的容错策略应该有一定的调用次数限制,譬如允许最多重试三个服务,如果都发生报错,那还是会返回调用失败。原因不仅是因为重试是有执行成本的,更是因为过度的重试反而可能让系统处于更加不利的状况。

快速失败(Failfast):还有另外一些业务场景是不允许做故障转移的,故障转移策略能够实施的前提是要求服务具备幂等性,对于非幂等的服务,重复调用就可能产生脏数据,引起的麻烦远大于单纯的某次服务调用失败,此时就应该以快速失败作为首选的容错策略。譬如,在支付场景中,为了避免重复扣款,此时最恰当可行的方案就是尽快让服务报错,坚决避免重试,尽快抛出异常,由调用者自行处理。

广播调用(Broadcast):广播调用与并行调用是相对应的,都是同时发起多个调用,但并行调用是任何一个调用结果返回成功便宣告成功,广播调用则是要求所有的请求全部都成功,这次调用才算是成功,任何一个服务提供者出现异常都算调用失败,广播调用通常会被用于实现“刷新分布式缓存”这类的操作。

断路器

断路器的基本思路是很简单的,就是通过代理(断路器对象)来一对一地(一个远程服务对应一个断路器对象)接管服务调用者的远程请求。断路器会持续监控并统计服务返回的成功、失败、超时、拒绝等各种结果,当出现故障(失败、超时、拒绝)的次数达到断路器的阈值时,它状态就自动变为“OPEN”,后续此断路器代理的远程访问都将直接返回调用失败,而不会发出真正的远程服务请求。避免服务雪崩

服务熔断和服务降级之间的联系与差别。断路器做的事情是自动进行服务熔断,这是一种快速失败的容错策略的实现方法。在快速失败策略明确反馈了故障信息给上游服务以后,上游服务必须能够主动处理调用失败的后果,而不是坐视故障扩散,这里的“处理”指的就是一种典型的服务降级逻辑,降级逻辑可以包括,但不应该仅仅限于是把异常信息抛到用户界面去,而应该尽力想办法通过其他路径解决问题,譬如把原本要处理的业务记录下来,留待以后重新处理是最低限度的通用降级逻辑。

全部评论

相关推荐

美团开奖了,谁说测开比后端薪资低?谁说前端比后端薪资低?好了你又要说后端可以争取sp、ssp,但是能拿到美团白菜offer的就已经算是人中龙凤了,拿到sp、ssp更是凤毛麟角!依旧劝退后端!你后端学历内卷炼狱!实习经历卷的爆!甚至无法入行!入行了也只是和测开、前端的一般!1.学历,最痛的一击!后端工程师的第一步,走得不是技术,而是学历!想要进入大厂?好好看清楚自己的身份证:没有名校背景,别想着进美团、字节、腾讯! 面试官看你的第一眼就会想:“呵,去,给你点面试机会,看看你的技术!”什么?你说自己有技术?不好意思,来点GitHub链接,Project经历,能让面试官笑着赶你走。你没个985、211,双一流,根本就无法站稳在这场技术竞赛的起点。你想进大厂,没学历,没技术!永远只有一个词—— “被无情拒绝”。2. 薪资:你不过是和前端、测开的一匹马“后端工程师薪资高?能进SSP就是牛逼!”SSP? 听起来像是你梦想的银河,但实际上能拿到这个级别的人 凤毛麟角,除非你在面试官面前像神话人物一样打了个响指,否则你连SSP的尾巴都摸不着。至于你说的“前端薪资不高”?别逗了,前端都在笑你呢, 他们搞个页面,工资比你写个亿级请求接口还多。你说你辛辛苦苦优化API、调度缓存,别人搞个UI设计就能多拿几千块。前端已经不止是个展示层了,他们赚得比你还轻松,而你不过是服务器上疯狂跑“CRUD操作”的那只笨重的工蚁。3. 后端的真正意义:修 Bug,解决问题,下一份工作还是修 Bug有多少人觉得后端是系统架构、数据库优化的高端战场?醒醒吧! 后端的真正使命:维护旧项目,修复别人留下的烂摊子。你觉得自己能构建一个完美的系统?不!你只会一边修复技术债务,一边打着 “重构” 的旗号,换来的是 “重构再重构” 的无尽循环。而且,别告诉我你能专心写代码。你又要写代码,又要看服务器日志,没事还得帮别人 修崩的数据库,给前端数据源做“格式化”。你就是那块永远处于消耗型工作的 “万金油”。4. 晋升?哈哈哈,你是在做梦!你以为后端开发是一条顺风顺水的快速晋升路线?错! 你永远只能在一个“程序员”的岗位上打转,或者你为自己设立目标:“我要成为架构师”,那真的是在妄想。架构师?高级开发?靠近那条道路,你的心脏会先被晋升难度给捏住,你前方只有一座座高不可攀的技术山。别看那些SSP,架构师,架构啥呀?公司里的架构都是前端架构师,你就坐在后端的角落里,照顾着你那些满是错误的API和服务器。5. 加班?还是加班!你以为后端开发能像文艺片那样“偶尔加个班”?哈哈,傻了吧! 后端开发的生活是无休止的加班和修bug,你不仅要写接口,还得守夜调度、监控系统性能。就连你写的那个“完美的数据库查询”,也可能在 第二天 被前端因为“页面卡顿”给打回原形。“没有加班,你还能吃什么饭?”你说你是程序员,结果你的生活全是 熬夜加班、调试、重启。前端跑个页面,喝个咖啡就能过关,而你呢,熬夜跟数据库调试,最后还是那个穷忙的死循环。6. 技术天花板:架构?技术深度?笑死了!后端开发的天花板?那不过是个永远也摸不着的架构师“梦想”,你能掌握几款框架、几种数据库、两三套微服务架构,最后也不过是个 管理端的“搬运工”。你没办法“打破天花板”,更没有机会跳出“自己写个爬虫”或者“API接口”的死循环。技术深度?你也不过是 “技术债务”的修复者,一天到晚都在修补“老旧系统”的缺陷,偶尔听前端同学聊聊他们React、Vue的最新版本,你根本无法理解他们说的是什么。
开心小狗🐶:感觉后端有点像考研的0812,报名的时候都想冲0812,看不上0854。但是真入学了,不都是众生平等
点赞 评论 收藏
分享
评论
点赞
4
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务