Go实现网关服务

前言

基本功能

  1. 支持多种协议代理:tcp/http/websocket/grpc

  2. 支持多种负载均衡策略:轮询/加权轮询/一致性Hash

  3. 支持下游服务发现:主动探测/自动服务发现

  4. 支持横向扩容:加机器就能解决高并发

借助网关处理高可用、高并发

  1. 限流:请求QPS限制

  2. 熔断:错误率达阈值服务熔断

  3. 降级:确保核心业务可用

  4. 权限认证:拦截没有权限的用户

计算机网络基础

OSI七层网络协议与TCP/IP协议

image-20201014193343592

经典协议与数据包

数据包

image-20201014193624753

在物理层传输的是以太网帧,它由以太网首部(主要包含机器mac信息等)和IP数据包构成。

在网络层传输的是IP数据包,它由IP首部和TCP段构成。

在传输层传输的是TCP段,它由TCP首部和应用数据构成。如果应用数据过大则会进行拆包,那么需要在应用数据中数据的包定义起点、终点。

在应用层传输的是应用数据,它由应用头部和用户数据构成。

HTTP协议

HTTP协议是明文传输的。

如下是HTTP的请求报文和响应报文

image-20201014194613130

Websocket握手协议

基于HTTP协议实现,完成连接后以二进制流方式进行传输

image-20201014194822267

Websocket数据包

image-20201014195012535

三次握手与四次挥手

三次握手

image-20201014195350112

四次挥手

image-20201014195447121

抓包分析三次握手和四次挥手

命令:tcpdump -n -S -i eth0 host www.baidu.com and tcp port 80

image-20201014200427763

为什么关闭方要等待2MSL?

  1. 保证连接可靠关闭

  2. 保证所有数据都传输完成

为什么会大量close_wait?

  1. 并发请求数太多导致的

  2. 被动关闭方未及时释放端口资源导致

close_wait一般出现在被动关闭方

TCP流量控制

流量控制来控制通讯双方数据发送的频率

由于通讯双方网速不同。任一方数据发送过快都会导致对方消息处理不过来,一般会先把数据放到缓存区中。如果缓冲区满了,发送方还在疯狂发送数据,数据包将会被丢弃。因此我们需要控制发送频率,TCP则是通过流量控制来控制发送频率。

image-20201014201934777

TCP拥塞控制

拥塞控制用来调节网络的负载

接收方网络资源繁忙,因未及时响应ACK导致发送方重传大量数据,将是的网络更加拥堵。拥塞控制可以动态调整窗口大小,不只是依赖缓冲区大小确定窗口。

慢启动和拥塞避免

image-20201014203306434

在慢启动阶段从1开始以2倍扩大的方式指数增长至慢启动阈值,接着进入拥塞避免加法增大(每次增大1),如果遇到网络拥塞的情况则会直接将窗口置为1,慢启动阈值置为原来的一般,继续进入慢启动阶段。

快速重传和快速恢复

image-20201014203836336

最开始仍然采用慢启动和拥塞避免算法。不同的是在收到3个重复ACK执行快重传,快重传(乘法减小)是将拥塞窗口降为原来的一半,将拥塞避免的阈值也降为原来的一半,接着进入快速恢复阶段。快速恢复对数据进行重传,重传完毕后,进入拥塞避免(加法增大)。

为啥会出现粘包、拆包,如何处理?

image-20201014205744465

应用程序写入的数据大于套接字缓冲区大小,将会发生拆包。

进行MSS(最大报文长度)大小的TCP分段,当TCP报文长度 - TCP头部长度 > MSS时将发生拆包。

应用程序写入的数据小于套接字缓存区大小,网卡将应用多次写入的数据发送到网络上,将发送粘包。

接收方法不及时读取套接字缓冲区数据,将发生粘包。

如何获取完整的应用数据报文?

  1. 使用带消息头的协议,头部写入包长度,然后读取包内容。

  2. 设置定长消息,每次读取定长内容,长度不够时空位补固定字符。

  3. 设置消息边界,服务端从网络流中按消息边界分离出消息内容,一般使用

  4. 在应用层我们还可以直接选择如protobufjson等协议。

基于go实现TCP、UDP、HTTP服务器与客户端

TCP

服务端

客户端

UDP

服务端

客户端

HTTP

服务端

客户端

net包阅读(有一定难度,建议看完如Gin等库实现后再看)

网络代理

网络代理和网络转发的区别

网络代理

用户不直接连接服务器,网络代理去连接。获取数据后返回给用户。

用户通过代理请求信息,请求通过网络代理完成转发到达目的服务器,目标服务器响应后再通过网络代理回传给用户。

image-20201015191826326

网络转发

是路由器对报文的转发操作,中间可能对数据包修改。

image-20201015191901825

网络代理类型

正向代理

是一种客户端的代理技术,帮助客户端访问无法访问的服务资源,可以隐藏用户真实IP。比如:浏览器web代理、VPN等。

正向代理示例:实现一个简单的浏览器代理

反向代理

是一种服务端的代理技术,帮助服务器做负载均衡、缓存、提供安全校验等,可以隐藏服务器的真实IP。比如:LVS技术、nginx等

image-20201015194635411

反向代理示例:简单的服务器代理

代理

服务器

演示

HTTP代理

功能:

  1. 错误回调及错误日志处理

  2. 更改代理返回内容

  3. 负载均衡

  4. URL重写

  5. 限流、熔断、降级

  6. 数据统计

  7. 权限认证

ReverseProxy功能点

  1. 支持更改内容

  2. 错误信息回调

  3. 支持自定义负载均衡

  4. URL重写功能

  5. 连接池

  6. 支持Websocket服务(后续介绍)

  7. 支持HTTPS代理(后续介绍)

在net/http/httputil下定义了ReverseProxy

基于ReverseProxy实现简易的HTTP代理

ReverseProxy更改内容支持

特殊的Header头

"X-Forwarded-For": 标记客户端地址每个方向服务器代理的IP

"X-Real-IP": 我的实际请求的标记

"Connection": 标记连接是关闭、长连接等状态

"TE": 标记传输类型是什么

"Trailer": 允许发送方在消息后面添加的一些源信息

拓展ReverseProxy功能

负载均衡

  1. 随机负载:随机挑选目标服务器IP

  2. 轮询负载:遍历服务器列表

  3. 加权负载:给目标设置访问权重,按权重轮询(参考Nginx的负载均衡)

    加权轮询

  4. 一致性Hash负载:请求固定URL访问指定IP

HTTPS代理

Websocket代理

TCP代理

中间件(可以参考Gin)

洋葱结构的原理

go中间件数据传递

中间件实现

中间件一般都封装在路由上,路由是URL请求分发的的管理器。

基于数据构建中间件,使用灵活,控制方便。基于链表实现不仅复杂,且难以调用。

责任链模式(基于链表构建)

方法切片模式(基于数组构建)

方法组装

  1. 构建中间件路由

  2. 构建URL的中间件方法数组

  3. 使用use方法整合路由与方法数组

image-20201016215511479

方法调用

  1. 构建方法请求逻辑

  2. 封装http.Handler接口与http.Server整合

image-20201016215820640

中间件的意义

  1. 提高复用、隔离业务。将公共逻辑剥离

    image-20201017113106390

  2. 调用清晰、组合随意

    image-20201017123125967

参考

Golang Web入门(3):如何优雅的设计中间件

限流和熔断降级

限流

高并发系统的三大利器:缓存、降级、限流

缓存:提升业务系统访问速度和增大处理容量,为相应业务增加缓存。

降级:当服务器压力剧增时,根据业务策略降级,以此释放服务资源保证业务正常。

限流:通过对并发限速,以达到拒绝服务、排队或等待、降级等处理。

限流原理

  1. 漏桶限流:每次请求时计算桶流量,超过阈值则降级请求。

    image-20201017160329470

  2. 令牌桶限流:每次请求时从令牌桶里取出令牌,取不到则降级请求。

    image-20201017160408401

网关集成限流

熔断降级

熔断器是当依赖的服务已经出现故障时,为了保证自身服务的正常运行不再访问依赖的服务,防止雪崩效应。

降级是当服务器压力剧增时,根据业务策略降级,以此释放服务资源保证业务正常。

熔断器的三个状态

  1. 服务关闭:服务正常,维护失败率统计,达到失败率阈值时,转到开启状态。

  2. 开启状态:调用fallback函数,一段时间后,进入半开启状态。

  3. 半开启状态:尝试恢复服务,失败率高于阈值,进入开启状态,低于阈值,进入关闭状态。

熔断降级原理

image-20201017164146851

网关集成熔断降级

选择go类库:hystrix-go

Websocket

WebSocket协议

image-20201017192553837

请求URL如ws://127.0.0.1:2002/echo,以ws开头表示协议是websocket

Websocket数据传输协议

image-20201017193117906

Connection Header头意义

标记请求发起方与第一代理的状态

决定当前事物完成后,是否关闭网络

  • Connection: keep-alive 不关闭网络

  • Connection: close 关闭网络

  • Connection: Upgrade 协议升级

Websocket代理服务器

HTTP、HTTPS、HTTP2

HTTPS与HTTP的区别

HTTPS是HTTP协议的安全版本,HTTP协议的数据传输是明文的,是不安全的,HTTPS使用了SSL/TLS协议进行了加密处理

HTTP默认端口是80,HTTPS默认端口是443。

HTTPS请求流程:

image-20201017212151871

HTTP2和HTTP

  1. HTTP2采用二进制格式而非文本格式。

  2. HTTP2使用一个连接实现多路复用。

  3. HTTP2压缩了报头,降低了开销。

  4. HTTP2让服务器可以将响应主动“推送”到客户端缓存。

HTTP2和HTTPS的关系

  1. HTTP2代表多路复用的传输协议

  2. HTTPS代表HTTP服务器使用了加密传输

  3. 一个启用HTTPS的服务器不一定使用HTTP2

  4. 但是使用HTTP2的服务器必须启动HTTPS(浏览器强制)

HTTP2的补充

HTTP2设计目标

  1. 大多数情况下的感知延迟要有实质上改进

  2. 解决HTTP1.1中“队首阻塞”问题

  3. 并行操作无需与服务器建立多个连接

  4. 保持HTTP1.1的语义,只是标准拓展非替代

HTTP2基本概念

  1. 流:流是连接中的一个虚拟信道,可以承载双向的消息

  2. 消息:是指逻辑上的HTTP消息,比如请求、响应等

  3. 帧:HTTP2通信的最小单位,没个帧包含帧首部,至少会标识出当前帧所属的流,承载着特定类型的数据。

HTTP2多路复用

HTTP2首部压缩

HTTP2协议磋商

  1. 询问服务器是否支持HTTP2,不支持则将为HTTP1.1

    • 发起带有HTTP2 Upgrade首部的HTTP1.1请求

    • 服务端拒绝升级,通过HTTP1.1返回响应

    • 服务器接受HTTP2升级,切换到新分帧

TCP代理

四层负载均衡和七层负载均衡

路由转发客户端和服务器之间有一次三次握手

反向代理客户端和服务端之间有两次三次握手

四层负载均衡(路由转发)

image-20201018181534845

NAT作用于内核运行的

七层负载均衡(反向代理)

image-20201018181646281

代理是用户程序运行的。代理的数据会进入程序buffer中

gRPC透明代理

数据库表整理与创建

设计原则:数据库三大范式

  1. 列不可再分:如服务名、服务描述等属性不可再进一步拆分了。

  2. 属性完全依赖于主键:服务名依赖于服务ID

  3. 属性直接依赖于主键

E-R图

最后更新于

这有帮助吗?