(一)分布式调用
服务和应用的调用基于场景的不同会分为几种情况:
1 系统外的客户端调用系统内的服务时需要通过反向代理和负载均衡的方式;
2 系统架构内部服务之间的调用需要通过 API 网关;
3 服务之间的互相感知需要用到服务注册与发现;
4 服务之间的通信会使用 RPC 架构;
负载均衡:
分布式系统的拆分就是用更低的成本支撑更大的访问量,用更廉价的服务器集群替代性能强劲的单体服务器。随着业务量的扩大需要更多服务器作为支持,用来提升系统整体的处理性能,这也就是服务器集群。高性能集群的本质是将同一个服务扩展到不同的机器上,每次请求该服务时选其中一台服务器提供响应,也就是说这个请求无论在哪台服务器上执行,都能得到相同的响应。因此高性能集群的设计主要体现在请求分配上,说白了就是将请求按照一定规则分配到不同的服务器上执行,我们把这个分配过程叫作负载均衡,完成负载均衡的组件或者应用叫作负载均衡器。
根据使用场景的不同,还可将负载均衡分为 DNS 负载均衡、硬件负载均衡和软件负载均衡。同时需要注意负载均衡并非将请求“平均”分配,在分配时需要考虑策略,例如按照服务器负载进行分配、按照服务器性能进行分配、按照业务进行分配,这些分配规则就是负载均衡算法。

DNS(Domain Name System,域名系统)是互联网的一项服务。它将域名和 IP 地址的相互映射保存在一个分布式数据库中,使人们能够更方便地访问互联网。DNS 服务器用来实现区域级别的负载均衡。例如使华北用户访问华北机房的服务器、使华中用户访问华中机房的服务器,本质是通过 DNS 服务器再解析 URL 以后,返回对应机房的入口 IP 地址。
硬件负载均衡顾名思义就是通过硬件设备来实现负载均衡功能。硬件负载均衡器和路由器、交换机一样,作为基础的网络设备,架设在服务器集群之上,客户端通过它们与集群中的服务器实现交互。硬件负载均衡器所处的位置决定了其能够比 DNS 负载均衡器支持更多的负载均衡算法,比软件负载均衡器拥有更高的并发量。

软件负载均衡是指在一台或多台服务器的操作系统上安装一个或多个软件来实现负载均衡。一般来说将软件负载均衡所在的这一层称作代理层,起承上启下的作用,上连接入层(硬件负载均衡),下接应用服务器。在代理层可以实现反向代理、负载均衡以及动态缓存与过滤的功能。
● 反向代理和负载均衡
一般来说,应用服务器与互联网之间会加一个反向代理服务器,它先接收用户的请求,然后将请求转发到内网的应用服务器,充当外网与内网之间的缓冲。反向代理服务器除了起到缓冲作用外,还起路由资源的作用。代理层虽然可以处理一定程度的并发请求,但是当请求量非常大时,可以在代理层上加入接入层来承载大流量。

负载均衡算法:
以Nginx为例,常见的负载均衡算法有如下几种:
1 round-robin:轮询算法,是负载均衡默认使用的算法。说白了就是挨个查询上游服务器。
2 weight:权重算法,给应用服务器设置权重值。weight 参数的默认取值为 1,其值越大,代表服务器被访问的几率越大。可以根据服务器的硬件配置设置weight 值,让资源情况较乐观的服务器承担更多访问量。
3 IP-hash:这个算法可以根据用户 IP 进行负载均衡,来自同一 IP 的用户请求报文由同一台上游服务器响应,可以让同一客户端的会话(session)保持一致。这样即便设置了权重,从同一 IP 地址发出的用户请求可以还是访问同一台服务器
4 hash key:这个算法是对 IP-hash 算法的补充。当增加、删除上游服务器时,来自同一 IP 地址的请求可能无法正确地被同一服务器处理。出于对这一问题的考虑,为每个请求都设置 hash key,这样就算服务器发生了变化,只要请求的 key 值没有变,还是可以找到对应的服务器。
5 least_conn:该算法把请求转发给连接数较少的后端服务器。轮询算法是把请求平均转发给各个后端服务器,使它们的负载大致相同。但是,有些请求占用的时间会很长,导致其所在的后端服务器负载较高。这种情况下,least_conn 算法能够获得更好的负载均衡效果。
● 动态缓存与过滤
软件负载均衡位于系统的入口,流入分布式系统的请求都会经过这里,换句话说,相对整个系统而言,软件负载均衡是离客户端更近的地方,所以可以将一些不经常变化的数据放到这里作为缓存,降低用户请求访问应用服务器的频率。

API网关
从业务层面讲,客户端完成某个业务需要同时调用多个微服务。如果这些服务需要客户端分别调用才能完成,必然会增加请求的复杂度,同时带来网络调用性能的损耗。因此,针对微服务应用场景推出了 API 网关的调用。在客户端与微服务系统之间加入下单 API 网关,客户端直接给这个 API 网关下达命令,由其完成对其他三个微服务的调用并且返回结果给客户端。

服务注册中心:
分布式系统内的服务之间是如何相互调用的呢?最简单的想法是服务 A 只需要知道服务 B 的地址和输入参数就可以对其调用了。如果服务 B 进行了水平扩展,则由多个服务 B 共同完成一个业务功能,此时服务 A就有可能只调用多个服务B中的一个。至于具体调用哪一个可以通过负载均衡算法确定。
服务B作为被调用方,会把自己的调用地址发送到服务 A,服务 A 在自己的 Nginx 上配置访问服务 B 的地址,也就是说服务 A 知道该如何访问服务 B。这样的配置方法虽然看上去解决了服务之间的调用问题,但是作为被调用方的服务B 如果地址进行了不当调整,例如新增了服务或者有的服务已下线,就需要通知调用方服务 A 修改路由地址。服务的调用方和被调用方之间需要长期维护这样一个关于调用的路由关系,在服务比较多的情况下需要维护很多这样错综复杂的关系,势必会增加系统的负担,因此引入了服务注册与发现的概念。
注册与发现原理:
分布式系统(或者说微服务系统)中存在着各种各样的服务,这些服务存在调用其他服务和被其他服务调用的情况。被调用的服务称作服务提供者,调用其他服务的服务称作服务消费者。
在服务提供者和服务消费者中间加入服务注册中心的概念,假设存在一个服务提供者和一个服务消费者,当服务提供者启动时,会主动到服务注册中心注册自己提供的服务。同样服务消费者启动时,也会根据自己消费的服务向服务注册中心订阅自己需要的服务,通常服务消费者会在本地维护一张服务访问的路由表,这个路由表中记录着访问服务提供者需要的路由信息。假如服务提供者不提供服务了,或者有新的服务提供者加入服务注册中心,服务注册中心将会更新服务提供者列表,与此同时主动通知服务消费者这一变更。服务消费者接收到变更信息以后,会刷新本地存储着的路由表,始终保证用正确的路由信息去调用服务提供者。

API网关、服务注册于发现。都是讲述服务与服务如何发现对方,如何选择正确路径进行调用,描述的是服务之间的关系。