★微服务系列

微服务1:微服务及其演进史

微服务2:微服务全景架构

微服务3:微服务拆分策略

微服务4:服务注册与发现

微服务5:服务注册与发现(实践篇)

微服务6:通信之网关

1 概述

回顾下前面几篇关于微服务的介绍,我们可以了解到从当单体系统到微服务,再到服务网格的演进过程。那单体系统和微服务相比,有哪些区别呢,下面是对功能性的对比?

单体系统 微服务系统
程序、数据、配置集中管理 按照功能拆分、微服务化、松耦合
开发效率低下 分模块快速迭代
发布全量,启动慢 平滑发布,快速启动
可靠性差 熔断、限流、降级,超时重试,异常离群
服务内直接调用 轻量级通信
技术单一 跨语言

微服务有诸多的有利条件,但是如果微服务的粒度比较细(按照业务功能拆分),则他们之间服务调用就会比较复杂,链路会比较长。

比如上图中,我们按照职能将服务进行了拆分,这时候从不同的客户端(如Web、App、3rd)访问,就有可能访问不同的服务。而服务与服务之间又有上下游的协作,调用就变得错综复杂。

因此,在微服务架构体系下,服务间的通讯就显得非常重要。

你可能需要关注很多问题,包括不同的技术栈不同的开发语言之间的上下游交互,服务之间的注册与发现,请求认证,接入授权。

下游对上游进行调用的时候,上游怎么做负载均衡、故障注入、超时重复、熔断、降级、限流、ABTesting等,端到端之间如何实现监控和trace,这些都是微服务体系下需要去思考的问题。

要解决上面这些问题,微服务通信可以从三个方面进行讨论

细化服务颗粒:按照功能拆分、微服务化、松耦合

分模块快速迭代:可以将应用程序拆分为核心和非核心模块。非核心模块出现问题的时候,核心模块不会受到影响。

参考这篇《微服务3:微服务拆分策略

流量管理:金丝雀发布,ABTesting

实现服务的高可用治理:熔断、限流、降级,超时重试,异常离群

轻量级通信,使用 RESTful API 或者 RPC 进行接口访问

跨语言,语言有特定的应用场景,比如go和Java、c++适合不同的业务方向,开发语言不同,但是遵循同一套标准,

使用轻量级的API进行通信,实现服务语言上的解耦。

2 服务之间的通信方式

而微服务的通信,是在服务之间增加一个间接的中间层来完成服务间的通信过程。目前微服务的通信方式有以下三种:

1、基于网关的通信

2、基于RPC的通信

3、基于ServiceMesh的数据面(SideCar)的通信

接下来逐一介绍这三种通信方式的具体实现,本文先介绍基于网关的通信方式。

2.1 基于网关的通信

我们先看看,在没有网关的情况下,服务是怎么通信的?

如上图有3个客户端,在调用4个服务的接口。这种直连调用的方式有很多问题:客户端需要保存所有服务的地址,同时也需要实现一些系统级的容错策略。

比如负载均衡、超时重试、服务熔断等,非常复杂,并且难以维护。因为是在各客户端保存的服务地址,一旦某个服务端出现问题或者发生迁移,所有的客户端都需要修改并且升级。

另外如果再增加一个E svc,所有的客户端也需要升级。而且在某些场景下存在跨域请求的问题,每个服务都需要实现独立的身份和权限认证等等。

这些问题导致 服务间的通信过于复杂,对于开发和维护都不优化。

如果我们在客户端和服务端增加一层网关,所有请求都经过网关转发到对应的下游服务,客户端只需要保存网关的地址并且只和网关进行交互,这样就大大简化了客户端的开发。

如果需要访问用户服务,只需要构造右边这个请求发给网关,然后由网关将请求转发给对应的下游服务。

可以将网关简单理解为:路由转发+治理策略,治理策略是指和业务无关的一些通用策略,包括:负载均衡,安全认证,身份验证,系统容错等等

网关作为一个 API 架构层,用来保护、增强和控制对服务的访问。

2.1.1 网关的主要功能

请求接入

1、为各种应用提供统一的服务接入

2、管理所有的接入请求:提供流量分流、代理转发、延迟、故障注入等能力

安全防护

用户认证、权限校验、黑白名单、请求过滤、防web攻击

治理策略

负载均衡、接口限流、超时重试、服务熔断、灰度发布、协议适配、流量监控、日志统计等

统一管理

1、提供配置管理工具

2、对所有服务进行统一管理

3、对中介策略进行统一管理

2.1.2 网关使用场景

蓝绿部署

我们前面看到,在单体应用中,部署是一件比较麻烦的事情,每次的改动,都需要把整个应用程序都发布启动一次。而且系统规模越大,部署过程越复杂,时间越长。

而在微服务架构中,模块部署起来相对更快,更容易。你可以在短时间内对于同一个模块做多次部署,网关可以帮你实现蓝绿部署。

如图所示之前的用户服务版本是V1.0,然后部署V1.1版本,在网关上只需要做一个转发配置的修改,就可以迅速的将所有流量都流到新版本。

灰度发布

类似金丝雀的理念,你对一次性升级版本感到担忧,可以先配置5%的流量达到新版本,让部分人试用一下,等线上观察一段时间后,可以逐步增加对新版本的流量百分比,最终实现百分之百切流。

负载均衡

此能力需要依赖服务注册和服务发现。

服务熔断

网关还可以实现断路器的功能;如果某个下游忽然返回了大量错误,原因有可能是服务挂了或者网络问题或者服务器负载太高,如果此时继续给这个问题服务转发流量就可能会产生级联故障。

出问题的服务有可能产生雪崩,雪崩会沿着调用链向上传递,导致整个服务链都崩溃。

断路器可以停止向问题模块转发流量,在业务层面可以给用户返回一个服务降级之后的页面,开发人员就有相对充分的时间来定位和解决问题。

2.1.3 开源网关

目前常见的开源网关按照语言大概分为上图的五种,如果按照使用数量和成熟度来划分的话,主流有4个,分别是 OpenResty、Kong、Zull和Spring Cloud。

其中 Zull 和Spring Cloud 是用java 实现,前两种是用Nginx+Lua实现的,其中,OpenResty 是一个基于Nginx+Lua实现的一个高性能web 平台,它集成了大量的第三方模块和lua库,用于方便的搭建高性能扩展性强的web 应用服务或者网关,

Kong 是一个基于OpenResty实现的一个高性能可扩展的API网关。从性能上来说:Kong的性能是最好的,其次分别是OpenResty、Spring Cloud 和Zuul。

2.1.4 Nginx介绍

大家熟悉的Nginx是用C语言实现的一个开源、跨平台、高性能的HTTP和反向代理Web服务器,具有高度模块化、扩展性强、轻量级、资源消耗少、高并发、高性能等特点。

Nginx进程模型

Nginx是一个多进程模型,包含一个master 进程和多个worker 进程。

master 进程主要负责接收外部信号,向各个worker 进程发送信号,监控worker 进程的状态。当worker 进程异常退出后,服务不会中断的。master 进程会迅速拉起新的worker 进程来工作。基本的网络事件比如读写,都是在worker 进程来实现。

多个worker 进程是相互独立的,他们共同竞争来自客户端的请求,一个请求只能在一个worker 中进行处理。

Nginx网络模型

首先,master 进程会listen socket,然后再fork出多个worker 进程,每个worker 进程都可以去accept 这个socket。
Nginx 提供了一把共享accept mutex锁来保证只有一个worker 进程可以把这个请求accept 成功。当这个worker 进程accept 连接成功之后,就可以进行请求的解析读取。

大概数据流:master 先 fork 多个worker 进程,然后当有client 来的时候,client 会连接到一个worker 进程里面,发送消息request。worker 进程再去读取、解析并处理,最终把response 返回给客户端。

那么大家可以想一下这个问题,Nginx 采用了一个多worker 的方式来处理请求,每个worker 里面其实是只有一个主线程,那么它是怎么实现高并发的呢?

答案是采用异步非阻塞的方式;什么是异步非阻塞?

举个例子,当worker 收到一个来自client request 时,就会有一个worker 进程去处理它。但这个worker 进程并不是全程处理,worker 会处理到请求可能会发生阻塞的地方。比如它向后端服务器转发的这个request,并等待请求的返回,

worker 进程不会同步的等待,而是注册一个事件,如果下游返回了,再继续处理这个事件。如果有新的请求再进来,它就可以很快按照这种方式再进行处理。这其实就是非阻塞和IO多路复用。

一旦服务端返回了,就会触发worker 刚才注册的回调事件,worker 才会继续接手这个request。

2.2 Zuul实战

刚才前面已经说过,网关是客户端和服务器之间的中间层,作为系统唯一对外的入口,能够处理流量治理、安全访问等工作。

功能类型 功能说明
统一接入 智能路由
  AB测试、灰度测试
  负载均衡、容灾处理
  日志埋点(类似Nignx日志)
流量监控 限流处理
  服务降级
安全防护 鉴权处理
  监控 
   机器网络隔离

业内主要的网关有如下几种:
1、zuul:是Netflix开源的微服务网关,可以和Eureka,Ribbon,Hystrix等组件配合使用,Zuul提供了动态路由、监控、弹性负载和安全功能。

2、kong: 由Mashape公司开源的,基于OpenResty(Nginx+Lua)的 API gateway。

3、Nginx + Lua:高性能的HTTP和反向代理服务器,Lua作为脚本语言,为Nginx提供执行程序,可以高并发、非阻塞的处理各种请求

下面我们以Zuul为案例,来测试下网关的使用。

2.2.1 配置路由规则

新建一个spring-clouid项目,导入Maven 依赖:

 1  <!-- eureka client -->
2 <dependency>
3 <groupId>org.springframework.cloud</groupId>
4 <artifactId>spring-cloud-netflix-eureka-server</artifactId>
5 </dependency>
6 <!-- zuul网关 -->
7 <dependency>
8 <groupId>org.springframework.cloud</groupId>
9 <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
10 <version>2.2.10.RELEASE</version>
11 </dependency> 

配置yaml文件:

 1 server:
2 port: 1002
3 spring:
4 application:
5 name: zuul-proxy # 服务的名称
6 eureka:
7 instance:
8 hostname: localhost
9 client:
10 service-url: # 这边就保证了注册到 eureka-service 这个注册中心去
11 defaultZone: http://localhost:1000/eureka/
12
13 #自定义路由映射
14 zuul:
15 routes: #路由规则
16 key-v1: #自定义key
17 path: /proxy/** # 匹配路径,/proxy/ 会路由到 zuul-proxy服务
18 serviceId: zuul-proxy
19 url: http://${eureka.instance.hostname}:${server.port}/zuulservice/api/v1.0/ # 只要路径匹配,就转到这个服务对应路径下 

Application中启动网关代理:

1 @SpringBootApplication
2 @EnableZuulProxy // 开启网关代理
3 public class ZuulGatewayApplication {
4 public static void main(String[] args) {
5 SpringApplication.run(ZuulGatewayApplication.class, args);
6 System.out.println("start zuulgateway!");
7 }
8 } 

接口实现:

 1 /**
2 * @author brand
3 * @Description:
4 * @Copyright: Copyright (c) 2021
5 * @Company: Helenlyn, Inc. All Rights Reserved.
6 * @date 2021/12/5 12:30 下午
7 * @Update Time:
8 * @Updater:
9 * @Update Comments:
10 */
11 @Controller
12 @RequestMapping("/zuulservice/api/v1.0")
13 public class ZuulServiceController {
14
15 /**
16 * 获取注册服务信息
17 */
18 @RequestMapping(value = "/serviceinfo", method = {RequestMethod.GET})
19 @ResponseBody
20 public String getServiceInfo() {
21 return "serviceinfo:v1.0,instance 1";

查看效果,proxy路由成功了:

2.2.2 测试负载均衡

我们在添加一个端口为1003的服务,跟端口为1002做zuul-proxy服务做负载均衡,这时候先修改 zuul-proxy 的yaml配置。

 1 # 自定义路由映射
2 zuul:
3 routes: # 路由规则
4 key-v1: # 自定义key
5 path: /proxy/** # 匹配路径,/proxy/ 会路由到 zuul-proxy服务
6 serviceId: zuul-proxy
7 ribbon:
8 eureka:
9 enabled: true # 允许Ribbon使用Eureka
10 zuul-proxy:
11 ribbon:
12 listOfServers: localhost:1002,localhost:1003 # 这边需要建立两个服务 1002,1003,在这两个服务间做负载均衡 

创建一个module,命名zuul-client,增加注册依赖

1         <!-- eureka client -->
2 <dependency>
3 <groupId>org.springframework.cloud</groupId>
4 <artifactId>spring-cloud-netflix-eureka-server</artifactId>
5 </dependency> 

配置zuul-client的yaml文件:

1 server:
2 port: 1003 # 这边注意,端口为1003,跟上面对应起来了
3 spring:
4 application:
5 name: zuul-client # 服务的名称
6 eureka:
7 client:
8 service-url: # 这边就保证了注册到 eureka-service 这个注册中心去
9 defaultZone: http://localhost:1000/eureka/ 

补充一个接口,注意返回的信息不一样:

 1 /**
2 * @author brand
3 * @Description:
4 * @Copyright: Copyright (c) 2021
5 * @Company:Helenlyn, Inc. All Rights Reserved.
6 * @date 2021/12/5 3:52 下午
7 * @Update Time:
8 * @Updater:
9 * @Update Comments:
10 */
11 @Controller
12 @RequestMapping("/zuulservice/api/v1.0")
13 public class ZuulServiceController {
14 /**
15 * 获取注册服务信息
16 */
17 @RequestMapping(value = "/serviceinfo", method = {RequestMethod.GET})
18 @ResponseBody
19 public String getServiceInfo() {
20 return "serviceinfo:v1.0,instance 2";
21 }
22 } 

网关 zuul-proxy 和 服务zuul-client都启动起来,可以看到如下的效果:

微服务6:通信之网关 Ready的更多相关文章

  1. Chris Richardson微服务翻译:构建微服务之使用API网关

    Chris Richardson 微服务系列翻译全7篇链接: 微服务介绍 构建微服务之使用API网关(本文) 构建微服务之微服务架构的进程通讯 微服务架构中的服务发现 微服务之事件驱动的数据管理 微服 ...

  2. spring cloud+dotnet core搭建微服务架构:Api网关(三)

    前言 国庆假期,一直没有时间更新. 根据群里面的同学的提问,强烈推荐大家先熟悉下spring cloud.文章下面有纯洁大神的spring cloud系列. 上一章最后说了,因为服务是不对外暴露的,所 ...

  3. spring cloud+.net core搭建微服务架构:Api网关(三)

    前言 国庆假期,一直没有时间更新. 根据群里面的同学的提问,强烈推荐大家先熟悉下spring cloud.文章下面有纯洁大神的spring cloud系列. 上一章最后说了,因为服务是不对外暴露的,所 ...

  4. Spring Cloud 微服务三: API网关Spring cloud gateway

    前言:前面介绍了一款API网关组件zuul,不过发现spring cloud自己开发了一个新网关gateway,貌似要取代zuul,spring官网上也已经没有zuul的组件了(虽然在仓库中可以更新到 ...

  5. .net core ——微服务内通信Thrift和Http客户端响应比较

    原文:.net core --微服务内通信Thrift和Http客户端响应比较 目录 1.Benchmark介绍 2.测试下微服务访问效率 3.结果 引用链接 1.Benchmark介绍 wiki中有 ...

  6. SpringCloud微服务笔记-Nginx实现网关反向代理

    背景 当前在SpringCloud微服务架构下,网关作为服务的入口尤为重要,一旦网关发生单点故障会导致整个服务集群瘫痪,为了保证网关的高可用可以通过Nginx的反向代理功能实现网关的高可用. 项目源码 ...

  7. 微服务架构中API网关的角色

    [上海尚学堂的话]:本文主要讲述了Mashape的首席技术执行官Palladino对API网关的详细介绍,以及API网关在微服务中所起的作用,同时介绍了Mashape的一款开源API网关Kong. A ...

  8. SpringCloud微服务项目实战 - API网关Gateway详解实现

    前面讲过zuul的网关实现,那为什么今天又要讲Spring Cloud Gateway呢?原因很简单.就是Spring Cloud已经放弃Netflix Zuul了.现在Spring Cloud中引用 ...

  9. 谈谈微服务中的 API 网关(API Gateway)

    前言 又是很久没写博客了,最近一段时间换了新工作,比较忙,所以没有抽出来太多的时间写给关注我的粉丝写一些干货了,就有人问我怎么最近没有更新博客了,在这里给大家抱歉. 那么,在本篇文章中,我们就一起来探 ...

随机推荐

  1. 《剑指offer》面试题38. 字符串的排列

    问题描述 输入一个字符串,打印出该字符串中字符的所有排列. 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素. 示例: 输入:s = "abc" 输出:["abc ...

  2. [开发笔记usbTOcan]PyUSB访问设备

    前面的几个章节的介绍,基本把usbTOcan的底层代码设计好,现在需要介绍PC端的PyUSB进行简单的测试. 在文章开始之前,需要简单的介绍一下整个系统. 0 | 部署 这里使用了两块TM4C123G ...

  3. 【VictoriaMetrics】vm-select源码阅读

    调用层次表格 源文件 行号 函数 说明 app/vmselect/main.go 63 main 入口 92行调用 requestHandler app/vmselect/main.go 132 -r ...

  4. 关于网页中鼠标动作 onfocus onblur focus()

    其中: onFocus事件就是当光标落在文本框中时发生的事件. onBlur事件是光标失去焦点时发生的事件. 例如: <textarea onfocus="if(hello') {va ...

  5. 第02讲:Flink 入门程序 WordCount 和 SQL 实现

    我们右键运行时相当于在本地启动了一个单机版本.生产中都是集群环境,并且是高可用的,生产上提交任务需要用到flink run 命令,指定必要的参数. 本课时我们主要介绍 Flink 的入门程序以及 SQ ...

  6. Python小练习-购物商城(一部分代码,基于python2.7.5)

    新手写作,用来练习与提高python编写.思考能力,有错误的地方请指正,谢谢! 第一次写博客,课题是一位大神的博客,本着练习的目的,就自己重写了一遍,有很多不足的地方,希望借博客记录下自己的成长:  ...

  7. HTTP-常用请求头

    HTTP-常用请求头 Accept:表示客户端可以接收的数据类型 Accpet-Language:表示客户端可以接收的语言类型 User-Agent:表示客户端浏览器的信息 Host:表示请求时的服务 ...

  8. rsync实时备份监控命令(详细大全)

    目录 一:rsync介绍 1.rsync简介 2.rsync特性 3.rsync应用场景 4.rsync的传输方式 5.Rsync传输模式 二:RSYNC使用参数 三:参数使用案例 一:rsync介绍 ...

  9. python内置re模块全面实战

    目录 一:取消转义 二:python内置模块之re模块 三:常用方法 findall search match 简便 四:常用方法 finditer 匹配文件多情况 五:切割 替换 内置模块 六:分组 ...

  10. kubernetes之添加删除node

    添加node 1.master生成token [root@node-01 ~]# kubeadm token create --print-join-command kubeadm join 172. ...