跳到主要内容

微服务相关

服务发现

参考文章 https://zhuanlan.zhihu.com/p/34332329

假设我们写的代码会调用 REST API 或者 Thrift API 的服务。为了完成一次请求,代码需要知道服务实例的网络位置(IP 地址和端口)。

运行在物理硬件上的传统应用中,服务实例的网络位置是相对固定的,代码能从一个偶尔更新的配置文件中读取网络位置。

对于基于云端的、现代化的微服务应用而言,这却是一大难题。将容器应用部署到集群时,其服务地址是由集群系统动态分配的。那么,当我们需要访问这个服务时,如何确定它的地址呢?这时就需要服务发现(Service Discovery)了。

服务发现是指使用一个注册中心来记录分布式系统中的全部服务的信息,以便其他服务能够快速的找到这些已注册的服务。

服务发现的角色

服务发现有三个角色,服务提供者、服务消费者和服务中介。

  • 服务中介是联系服务提供者和服务消费者的桥梁。(Redis可以作为服务中介)
  • 服务提供者将自己提供的服务地址注册到服务中介
  • 服务消费者从服务中介那里查找自己想要的服务的地址,然后享受这个服务。
  • 服务中介提供多个服务,每个服务对应多个服务提供者。

服务发现的模式

服务发现有两大模式:客户端发现模式和服务端发现模式。

客户端发现模式

使用客户端发现模式时,客户端决定相应服务实例的网络位置,并且对请求实现负载均衡。客户端查询服务注册表,后者是一个可用服务实例的数据库;然后使用负载均衡算法从中选择一个实例,并发出请求。

服务实例的网络位置在启动时被记录到服务注册表,等实例终止时被删除。服务实例的注册信息通常使用心跳机制来定期刷新。

客户端发现模式优缺点兼有。

这一模式相对直接,除了服务注册外,其它部分无需变动。此外,由于客户端知晓可用的服务实例,能针对特定应用实现智能负载均衡,比如使用哈希一致性。 这种模式的一大缺点就是客户端与服务注册绑定,要针对服务端用到的每个编程语言和框架,实现客户端的服务发现逻辑。

服务端发现模式

客户端通过负载均衡器向某个服务提出请求,负载均衡器查询服务注册表,并将请求转发到可用的服务实例。

Kubernetes 和 Marathon 这样的部署环境会在每个集群上运行一个代理,将代理用作服务端发现的负载均衡器。客户端使用主机 IP 地址和分配的端口通过代理将请求路由出去,向服务发送请求。代理将请求透明地转发到集群中可用的服务实例。

服务端发现模式兼具优缺点。

它最大的优点是客户端无需关注发现的细节,只需要简单地向负载均衡器发送请求,这减少了编程语言框架需要完成的发现逻辑。并且如上文所述,某些部署环境免费提供这一功能。 这种模式也有缺点。除非负载均衡器由部署环境提供,否则会成为一个需要配置和管理的高可用系统组件。

服务发现与负载均衡

服务发现和负载均衡的关系最后提到负载均衡这个概念是为后面文章做铺垫,因为它很容易和服务发现混淆,在很多简单的场景我们甚至也不去刻意区分它们。但本质上它们的层次和解决的问题是不一样的,简单说服务发现是负载均衡的前提,负载均衡要解决的是拿到服务列表后将流量合理的分配到各个节点上的问题

消息队列 MQ(Message Queue)

消息队列可以简单理解为:把要传输的数据放在队列中。把数据放到消息队列叫做生产者 从消息队列里边取数据叫做消费者

为什么要用消息队列

解耦:比如生产者A系统提供数据给BCDE系统,BCDE系统访问A的服务时一会这个要id,那个不要,就会导致重复去动Ad逻辑,这时候多一层消息队列,A将数据写入消息队列中,怎么取BCDE来自己个性化取,这样系统A就不用经常改动了,这样一来,系统A与系统B、C、D都解耦了

异步:系统A执行完了以后,将userId写到消息队列中,然后就直接返回了(至于其他的操作,则异步处理)。不用等BCDE一个一个调

削峰/限流:我A可以一秒请求3000次请求,bcde却承受不了,这时也可以先写到消息队列里,系统B和系统C根据自己的能够处理的请求数去消息队列中拿数据,这样即便有每秒有8000个请求,那只是把请求放在消息队列中,去拿消息队列的消息由系统自己去控制,这样就不会把整个系统给搞崩。

消息队列需要处理的问题

  • 高可用:队列不能崩溃挂了
  • 数据不能丢失: