什么是Gateway

在微服务体系结构中,如果每个微服务通常都会公开一组精细终结点,这种情况可能会有以下问题

  1. 如果没有 API 网关模式,客户端应用将与内部微服务相耦合
  2. 在客户端应用中,单个页面/屏幕可能需要多次调用多个服务。
  3. 如果没有网关,所有微服务必定会暴露在“外部世界”中。
  4. 每个公开发布的微服务都必须处理授权和 SSL 等问题。

而Gateway可以为微服务组提供单一入口点,API 网关位于客户端应用和微服务之间。 它充当反向代理,将请求从客户端路由到服务。 它还可以提供其他跨领域功能,例如身份验证、SSL 终止和缓存

什么是Envoy

Envoy 是专为大型现代 SOA(面向服务架构)架构设计的 L7 代理和通信总线,它有以下优势

  1. C++11编写,原生代码高性能
  2. L3/L4 filter架构,例如TCP代理
  3. HTTP L7 filter架构,缓存,限速,路由/转发
  4. 顶级HTTP2与GRPC支持
  5. 服务发现与动态配置
  6. 健康检查
  7. 高级负载均衡

我们可以借助Envoy实现API Gateway。Envoy通过yaml配置文件来组织网关的信息。下面来说说Envoy中的核心概念

Listener

一个命名的网络地址,可以被下游客户端连接,它的配置样式如下:

static_resources:
listeners:
- name: listener_0
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 10000

此配置说明Envoy监听在10000端口,下游客户端可以通过此端口与Envoy交互

L3/L4过滤器Filter

L3/L4过滤器Filter可以帮我们实现如:HTTP连接管理,限速,TCP代理等功能,它的配置样式如下:

    filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
scheme_header_transformation:
scheme_to_overwrite: http
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: "/"
route:
host_rewrite_literal: 192.168.43.94
cluster: service_envoyproxy_io
http_filters:
- name: envoy.filters.http.router

此配置说明通过HttpConnectionManager这个过滤器来接受HTTP请求,并将请求通过router过滤器的配置转发到service_envoyproxy_io这个上游集群

Upstream Cluster

Envoy 的集群管理器管理所有配置的上游集群,用来真正处理Envoy接受的请求,其配置样式如下:

clusters:
- name: service_envoyproxy_io
connect_timeout: 30s
type: strict_dns
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: service_envoyproxy_io
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 192.168.43.94
port_value: 5000

此配置说明Envoy会将请求转发到192.168.43.94:5000这个地址。

调用逻辑我们总结如下,Listener接受请求,将请求交给过滤器,过滤器处理完后,根据路由规则将请求转发给上游集群,上游集群中的endpoint会真正处理请求。

运行Envoy

我们通过docker运行一个默认Envoy容器

docker run --rm -it -p 9901:9901 -p 10000:10000 envoyproxy/envoy-dev

访问http://localhost:10000/,发现其跳转到Envoy官网

我们进入容器查看其配置,发现其最终会将请求转发到www.envoyproxy.io

cat /etc/envoy/envoy.yaml
      - lb_endpoints:
- endpoint:
address:
socket_address:
address: www.envoyproxy.io
port_value: 443

静态文件配置

我们现在通过Envoy来实现我们自己的网关。静态文件配置是我们把配置信息提前配置好,Envoy启动后不可修改配置内容

准备服务

我们准备两个.NET WebAPI,server1与server2,其中分别创建NameController,并新建Get方法

Server1

      [HttpGet]
public string Get()
{
_logger.LogInformation("call server1");
var req = Request;
return "server1";
}

Server2

        [HttpGet]
public string Get()
{
_logger.LogInformation("call server2");
var req = Request;
return "server2";
}

并将server1的启动端口指定为5000,将server2的启动端口指定为5001

Server1

webBuilder.UseUrls("http://*:5555").UseStartup<Startup>();

Server2

webBuilder.UseUrls("http://*:5001/").UseStartup<Startup>();

我们启动Server1与Server2

准备Envoy配置

我们将上节课的默认Envoy配置文件从容器中取出,并作修改如下

admin:
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 9901
static_resources:
listeners:
- name: listener_0
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 10000
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
scheme_header_transformation:
scheme_to_overwrite: http
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: "/"
route:
host_rewrite_literal: 192.168.43.94
cluster: service_envoyproxy_io

http_filters:
- name: envoy.filters.http.router
clusters:
- name: service_envoyproxy_io
connect_timeout: 30s
type: static
# Comment out the following line to test on v6 networks
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: service_envoyproxy_io
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 192.168.43.94
port_value: 5000
- endpoint:
address:
socket_address:
address: 192.168.43.94
port_value: 5001

我们启动Envoy,验证配置是否正确

docker run --rm -it -p 9901:9901 -p 10000:10000 -v D:/gateway/envoy/config/static/envoy.yaml:/etc/envoy/envoy.yaml -v D:/gateway/envoy/logs:/logs envoyproxy/envoy-dev  -c /etc/envoy/envoy.yaml --log-path logs/custom.log

调用api,发现其实现了负载

http://localhost:10000/Name

动态文件配置

动态文件可以帮助我们实现当文件发生更改时,Envoy 将自动更新其配置。

修改静态文件,将其中的cluster提取到cds.yaml文件中

resources:
- "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster
name: example_proxy_cluster
type: STRICT_DNS
typed_extension_protocol_options:
envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
"@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
explicit_http_config:
http_protocol_options: {}
load_assignment:
cluster_name: example_proxy_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 192.168.43.94
port_value: 5000

将listener提取到lds.yaml文件中

resources:
- "@type": type.googleapis.com/envoy.config.listener.v3.Listener
name: listener_0
address:
socket_address:
address: 0.0.0.0
port_value: 10000
filter_chains:
- filters:
- name: envoy.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
http_filters:
- name: envoy.filters.http.router
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains:
- "*"
routes:
- match:
prefix: "/envoyapi/"
route:
prefix_rewrite: "/"
host_rewrite_literal: 192.168.43.94
cluster: example_proxy_cluster

修改envoy.yaml让其引用lds.yaml与cds.yaml文件

admin:
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 9902
node:
cluster: test-cluster
id: test-id
dynamic_resources:
cds_config:
path: /etc/envoy/cds.yaml
lds_config:
path: /etc/envoy/lds.yaml

启动Envoy

docker run --rm -it -p 9902:9902 -p 10000:10000 -v D:/gateway/envoy/config/dynamic/:/etc/envoy/ -v D:/gateway/envoy/logs:/logs envoyproxy/envoy-dev  -c /etc/envoy/envoy.yaml --log-path logs/custom.log

调用api,发现调用成功

http://localhost:10000/envoyapi/Name

修改动态文件配置

修改cds.yaml,将endpoint端口设置为5001

resources:
- "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster
name: example_proxy_cluster
type: STRICT_DNS
typed_extension_protocol_options:
envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
"@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
explicit_http_config:
http_protocol_options: {}
load_assignment:
cluster_name: example_proxy_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 192.168.43.94
port_value: 5001

进入容器内部强制更新文件

# cd /etc/envoy
# mv cds.yaml tmp
# mv tmp cds.yaml

调用api,发现在不重启Envoy的情况下,实现了配置信息的动态更新

至此,我们已经通过Envoy的静态配置与文件动态配置实现了一个网关来代理我们的.NET程序

通过Envoy实现.NET架构的网关的更多相关文章

  1. Envoy实现.NET架构的网关(四)集成IdentityServer4实现OAuth2认证

    什么是OAuth2认证 简单说,OAuth 就是一种授权机制.数据的所有者告诉系统,同意授权第三方应用进入系统,获取这些数据.系统从而产生一个短期的进入令牌(token),用来代替密码,供第三方应用使 ...

  2. Envoy实现.NET架构的网关(二)基于控制平面的动态配置

    什么是控制平面 上一篇我们讲了文件系统的动态配置,这次我们来看看通过Control Panel来配置Envoy.控制平面就是一个提供Envoy配置信息的单独服务,我们可以通过这个服务来修改Envoy的 ...

  3. Envoy实现.NET架构的网关(三)代理GRPC

    什么是GRPC gRPC是一种与语言无关的高性能远程过程调用 (RPC) 框架.gRPC 的主要好处是: 现代.高性能.轻量级的 RPC 框架. 契约优先的 API 开发,默认使用协议缓冲区,与语言无 ...

  4. Envoy实现.NET架构的网关(五)集成Redis实现限流

    什么是限流 限流即限制并发量,限制某一段时间只有指定数量的请求进入后台服务器,遇到流量高峰期或者流量突增时,把流量速率限制在系统所能接受的合理范围之内,不至于让系统被高流量击垮.而Envoy可以通过e ...

  5. Spring Cloud构建微服务架构 - 服务网关

    通过之前几篇Spring Cloud中几个核心组件的介绍,我们已经可以构建一个简略的(不够完善)微服务架构了.比如下图所示: alt 我们使用Spring Cloud Netflix中的Eureka实 ...

  6. 京东的Netty实践,京麦TCP网关长连接容器架构

    背景 早期京麦搭建 HTTP 和 TCP 长连接功能主要用于消息通知的推送,并未应用于 API 网关.随着逐步对 NIO 的深入学习和对 Netty 框架的了解,以及对系统通信稳定能力越来越高的要求, ...

  7. .NET微服务架构及API网关

    一.MSA简介 1.1.MSA是什么 微服务架构MSA是Microservice Architecture的简称,它是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相通讯.互相配合, ...

  8. 浅析阿里云API网关的产品架构和常见应用场景

    自上世纪60年代计算机网络发展开始,API(Application Programming Interface )随之诞生,API即应用程序接口,是实现系统间衔接的桥梁.时至今日,API市场已经形成了 ...

  9. 实测 | 转型微服务,这4大工具谁是API网关性能最优?

    转自:http://www.servicemesh.cn/?/article/45 作者:Turgay Çelik 翻译:钟毅(Drew Zhong) 原文:Comparing API Gateway ...

随机推荐

  1. 全局CSS样式表

    看api手册使用即可 1.按钮和图片 2.表格.表单 表单的lable作用就是点击前面的文字可以聚焦到对应的输入框中

  2. Markdown快捷键详解(源自狂神说Java视频,整理版)

    #加空格 表示是一个标题(一级标题)回车后直接生成 例下 Markdown学习 标题: ##(两个#号)空格加标题名字即为二级标题例下 二级标题 三个#号 加标题名字即为三级标题,与二级标题等有层级关 ...

  3. 羽夏看Win系统内核——简述

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...

  4. RE Validation in JavaEE

    以下是关于RE校验的一些方法的基本功能: import java.util.regex.Pattern;<br> /** * 校验器:利用正则表达式校验邮箱.手机号等 * */<br ...

  5. 433MHZ SPI模块使用心得

    最近使用了433MHZ的模块进行了一个通讯项目,选用的是SX1208模块,对接了RTOS和Linux两个操作系统,使用心得如下: 1. 首先要拿来datasheet看一遍,通揽一下它的功能.可以得到一 ...

  6. 在PHP中检测一个类是否可以被foreach遍历

    在PHP中,我们可以非常简单的判断一个变量是什么类型,也可以非常方便的确定一个数组的长度从而决定这个数组是否可以遍历.那么类呢?我们要如何知道这个类是否可以通过 foreach 来进行遍历呢?其实,P ...

  7. Github新手入门

    git入门项目:https://guides.github.com/activities/hello-world/ 创建存储库 创建一个分支 进行并提交更改 打开拉取请求 合并您的拉取请求

  8. Redis5种常用数据类型的使用以及内部编码

    String 字符串类型是redis的最基本类型,首先无论值是什么数据类型,其键都是字符串,且其他数据类型的数据结构都是在字符串的基础上搭建的,相信读者能够体会到字符串在redis的地位是有多么的重要 ...

  9. go语言游戏服务端开发(四)——RPC机制

    五邑隐侠,本名关健昌,12年游戏生涯. 本教程以Go语言为例. RPC指远程方法调用,游戏里引入RPC目的是降低跨进程交互的复杂度. 游戏业务设计为多go routine,一个玩家一个go routi ...

  10. MacOS下Java与JDK关系与相关路径

    MacOS下Java与JDK关系与相关路径 macOS下的Java与JDK的路径曾经困扰过我一段时间,今天稍有些忘记,故记下笔记,整理一下.Java与JDK的关系不在本文笔记之内,Javaer常识. ...