微服务网关
2020-06-15 11:45:00 0 举报
AI智能生成
微服务网关
作者其他创作
大纲/内容
积木拼装
构建配置更新模块
代码实现
功能测试
接入tcp服务代理
代码整合
接入http服务代理
在线配置管理
实现一套AdminLTE后台
实现服务接口
实现租户接口
微服务网关
构建积木
网络基础知识(为何需要补充网络基础)
OSI七层网络模型 与 TCP/IP四层协议模型
经典应用
应用层:HTTP、FTP、Telnet、HTTP2、
传输层:TCP、UDP
网络层:ICMP、ARP
数据链路层
层次体系结构图
协议和数据包
整个数据包结构图
经典协议数据包图
TCP协议图
HTTP协议图
websocket协议图
tcp 协议拓展
三次握手、四次挥手
为啥time_wait需要等待2MSL?
MSL是啥?
(Maximum Segment Lifetime,30秒--1分钟)
四次握手图
1、确保ack发送成功可能对方buffer慢了丢包了都要重发
2、防止已失效报文重新请求连接。
参照:https://blog.csdn.net/q1007729991/article/details/69686781#commentBox
https://www.cnblogs.com/pengmn/p/10836784.html
为啥服务器会出现大量close_wait?
现象图:Too many open files。https://www.cnblogs.com/grey-wolf/p/10936657.html
直接上图贴代码未close样例
tcp 流量、拥塞控制
为什么会出现粘包、如何拆包?
回顾数据包结构
了解缓冲区的定位
传输过程图(带报文细节)
为啥会粘包?
应用程序写入的数据大于套接字缓冲区大小,这将会发生拆包。
应用程序写入数据小于套接字缓冲区大小,网卡将应用多次写入的数据发送到网络上,这将会发生粘包。
进行MSS(最大报文长度)大小的TCP分段,当TCP报文长度-TCP头部长度>MSS的时候将发生拆包。
接收方法不及时读取套接字缓冲区数据,这将发生粘包。
如何拆包?
使用带消息头的协议、消息头存储消息开始标识及消息长度信息,服务端获取消息头的时候解析出消息长度,然后向后读取该长度的内容。
设置消息边界,服务端从网络流中按消息编辑分离出消息内容,一般使用‘\’。
更为复杂的协议,如mqtt、json、protobuf
示例代码:
定义codec形式:https://segmentfault.com/a/1190000013493942
贴上自己的核心逻辑实现
如何获取完整数据报文?
定义数据格式:msg_header+content_len+content
编码_encode
解码_decode
tcp_client
1、连接服务器
2、数据编码
tcp_server
1.监听端口
2.接收请求
3.创建独立协程
4. 数据解码
拥塞控制图
窗口图
发送者与接收者图
流量控制
为啥使用流量控制
流量控制图
代码实操
udp服务器与客户端,代码演示
服务端
step 1 监听服务器
step 2 循环读取消息内容
step 3 回复数据
客户端
step 1 连接服务器
step 2 发送数据
step 3 接收数据
tcp服务器与客户端,代码演示
服务器
1、监听端口
2、建立套接字连接
3、创建处理协程
2、读取命令行输入
3、一直读取直到读到\
4、读取Q时停止
5、回复服务器信息
客户端未执行close,会一致使连接处于 ESTABLISHED
http服务器与客户端,代码演示
创建路由器
设置路由规则
创建服务器
监听端口并提供服务
创建连接池
创建客户端
请求数据
读取内容
服务器源码分析
理解函数一等公民
注册路由
type ServeMux struct{}
mu sync.RWMutex
m map[string]muxEntry
http.ServeMux.HandleFunc
Handle
mux.m[pattern] = e
开启服务
http.Server.ListenAndServe
Serve(l net.Listener)
go c.serve
处理请求
mux.Handler(r)
mux.match(path)
客户端源码分析
主要结构体
type Client struct {}
Transport RoundTripper
Timeout time.Duration
type RoundTripper interface {}
请求流程
func (c *Client) Get(url string)
c.Do(req)
c.do(req)
Transport 连接池
结构体
type Transport struct { idleMu sync.Mutex wantIdle bool // 用户是否已关闭所有的空闲连接 idleConn map[connectMethodKey][]*persistConn // 保存从connect 到persistConn的映射 idleConnCh map[connectMethodKey]chan *persistConn}
roundTrip流程
func (t *Transport) roundTrip(req *Request)
select
case <-t.incHostConnCount(cmKey): 确认每主机是否有限制?
case pc := <-t.getIdleConnCh(cm): 尝试获取连接
case <-req.Context().Done(): 一边监听取消事件
go pconn.readLoop() 一边读数据
监听 pconn.reqch,写入conn
go pconn.writeLoop() 一边写数据
监听 pconn.writech,写入conn
case v := <-dialc: 新增连接成功
case pc := <-idleConnCh: 有可用连接
pc.writech <- writeRequest
默认Client、Transport配置
超时时间概览图
Keepalived时间与IdleConnTimeout区别
server端连接 是由 客户端指定 keepalived 产生的
client端连接 是由 transport连接池设置的
keepalive是发送探活报时间间隔 https://blog.csdn.net/qq_42316690/article/details/80463992
网络代理
什么是网络代理
代理用户请求信息:用户真实请求通过网络代理完成转发到达目标服务器,目标服务器相应后再通过网络代理回传。
代理类型
正向代理:是一种客户端的代理技术,帮助客户端访问无法访问的服务资源,可以隐藏用户真实IP。比如:浏览器上设置web代理
正向代理图
代理原理图分析
先准备代码(上图),然后就是配置浏览器器(上图),然后就是请求浏览器正向代理功能演示这种正向代理技术不是我们研究的重点
核心代码逻辑
代理接收客户端请求,复制原请求对象,并根据数据配置新请求的各种参数
把新请求发送到服务端,并接收到服务器端返回
代理服务器对相应做一些处理,然后返回给客户端
反向代理:是一种服务端的代理技术,帮助服务器做负载均衡、缓存、提供安全校验等,可以隐藏服务器真实IP。比如:LVS技术、nginx_pass等
反向代理图
先准备代码(上图),然后演示结果也直接贴图,这个功能比较复杂我们稍后再详细讲述,引入http代理原理分析
代理接收客户端请求,更新请求服务器信息
把新请求发送到服务器,并接收到服务器端返回
拷贝返回请求头header信息,给客户端
拷贝返回请求内容,给客户端
更加详细的原理阐述 https://www.cnblogs.com/xuepei/p/10437114.html
http代理首先来个http代理的串讲,他们之间的相互关系
首先回顾一下上面章节讲到反向代理代码实现及原理
当前实现的http代理问题
无法设置:错误回调及错误日志处理
无法:更改代理返回内容
不支持:负载均衡
不支持:url重写
不支持:限流、熔断、
不支持:数据统计
不支持:权限验证
不支持:websocket协议
使用ReverseProxy实现一个http代理
只做一个简单功能演示
可以实现的功能有:
连接池功能
支持随机的负载均衡
贴图
后续我们会讲解各种负载均衡策略
更改内容支持
错误信息回调
url重写功能
支持websocket服务
后续讲解
支持https代理
都有哪些实现细节,我们一一来看看看它的难点有哪些?了解技术细节有利于我们分析问题
首先补充一下header知识:http header特殊头部详解虽然不常用,但是有利于理解 http代理实现细节引出为啥 connection hop 头?原理图说明为好
\"X-Forwarded-For\"
如果一个请求经过了多个代理服务器,那么每一个代理服务器的IP地址都会被依次记录在内
图片说明:https://www.cnblogs.com/diaosir/p/6890825.html
\"Connection\"
去除标准的逐段传输(hop-by-hop)头这些头定义了发出者和第一个实体之间的连接,而不是和目的地节点的连接。
一般值为:keep-alived/close
图片说明
\"TE\"不常用了解即可
request header
表示希望使用的传输编码类型
\"Trailer\"不常用了解即可
response header
允许发送方在消息后面添加额外的元信息
参见示例代码:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Trailer
再次补充一下statusCode知识:
100
http://www.laruence.com/2011/01/20/1840.html
101
状态码表示服务器应客户端升级协议的请求
HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: Upgrade
关于websocket 协议升级后期再讲解
明确核心结构体
核心方法:func (p *ReverseProxy) ServeHTTP
验证是否请求终止
设置请求 ctx 信息
深拷贝header
修改req
Upgrade头的特殊处理
追加clientIp信息
向下游请求数据
处理升级协议请求
移除逐段头部
修改返回内容
拷贝头部的数据
写入状态码
周期刷新到内容到response
拓展ReverseProxy功能
负载轮询
随机负载均衡
轮询负载均衡
加权负载均衡
算法分析核心逻辑:每论都计算出最大临时权重节点
每节点有三个变量:
weight 权重
currentWeight 临时权重
effectiveWeight 有效权重
算法逻辑
统计所有有效权重之和
变更节点临时权重为的节点临时权重+节点有效权重
选择最大临时权重点节点
变更临时权重为 临时权重-有效权重之和
请求次数分析:参考网页做下分析
一致性hash负载均衡
一致性hash算法
算法目标
新增或减少一台服务器以后,不会造成大面积的访问错误。
同一个资源仍然会映射到之前同样的服务器上。
新增一台服务器时,新的服务器需要尽量分担存储其他服务器的缓存资源。
少一台服务器时,其他服务器也可以尽量分担存储它的缓存资源
算法实现图
构建一个环形空间
crc32算法
把主机映射到环形空间上
对象可以沿顺时针查找cache
添加或移除cache,单调分析
添加虚拟节点,确保平衡性
来源ip
请求url
反向代理拓展负载均衡
使用工厂模式
使用接口封装统计方法
中间件支持后话,有了中间件就到了网关大显神通的时候了,我们的rpc、grpc、http都离不开它有了它就可以便捷加入你想要的功能了学习一遍之后可以触类旁通了
它处在HTTP request和HTTP response之间,用来实现某种功能,比如:日志、权限认证、限流等操作
实现原理
认识洋葱结构图
方法链条
责任链模式
实现思路
router 创建中间件链式结构
router 构造基于链表的方法链
router 实现ServeHTTP方法,方便引用调用
具体实现,因涉及多种回调和实现比较复杂一些我们简单过一下代码不必深究,下面还有一种控制灵活简单的方式
方法切片模式
router 用于构建中间件方法数组
routerContext 用于方法回放及方法控制
routerContext 实现ServeHTTP方法,方便引用调用
将核心代理方法传入即可完成代理功能
代码分析
后话,有了中间件就到了网关大显神通的时候了
限流、熔断高并发三大利器:缓存、降级、限流
限流
限流意义:对某一时间窗口请求数限制,保证系统可用性和稳定性。
漏桶算法 图讲解,考虑重新绘制
令牌桶算法 图讲解
代码示例
限流器提供三种使用方式
Allow
判断当前是否可以取到token
Wait
阻塞等待直到,取到一个token
Reserve
源码窥探
计算上次请求和当前请求时间差
计算时间差内可生成token数,求得token总数
计算每次请求后剩余 token 数
如果 token 未负数,计算等待时间
更新当前 token 数
https://www.jianshu.com/p/1ecb513f7632
限流代码我们暂时先不接入网关,我们接着往下学习
https://www.cnblogs.com/cjsblog/p/9379516.html
https://mp.weixin.qq.com/s?src=11&timestamp=1579832864&ver=2115&signature=H*QOdcw6ZEby2GpK*5T9cvg6nAX26XlV3rD2BOUWXMuQc5bigapyO6-xO80P3GSQ8lG-9dey2q9zSA6BuG6fcf5VxHuDNIX3w5ui0FcAHYjhEfYPPCgILATcB3CGLToK&new=1
https://mp.weixin.qq.com/s?src=11&timestamp=1579832361&ver=2115&signature=c6202A2BOxKWmK*-n6HM5CScwQy9QCuw1i4h2AMwWUL-rsNZrS3vCnSfB8wnc7AStbmL*IGPfempvhccouDaSzsJk-ou5XMN9fVyOH8b-ezbfBMyQ2hHzH2CDHUvhSFi&new=1
熔断原理
集限流、熔断、容错 类库 hystrix-go
使用方法示例
同步、异步二种方式
源码分析
流程图准备,从下面文档中获取
设置熔断配置 hystrix.ConfigureCommand(
执行熔断方法 hystrix.Do
func GoC(
GetCircuit(name)
newCircuitBreaker(name)
初始化交换统计 c.metrics = newMetricExchange
初始化指标收集器数组 m.metricCollectors = []DefaultMetricCollector
go m.Monitor()
for update := range m.Updates
go m.IncrementMetrics 记录到metric中
初始化执行池 c.executorPool = newExecutorPool(name)
p.Metrics = newPoolMetrics(name)
for u := range m.Updates {
更新时间窗数据m.Executed.Increment(1)m.MaxActiveRequests.UpdateMax(float64(u.activeCount))
生产并发数量个桶 p.Tickets <- &struct{}{}
sync.NewCond 通知锁使用方法
验证是否允许请求 cmd.circuit.AllowRequest
或 !circuit.IsOpen()
10秒内请求量小于熔断阈值直接返回false
10秒内错误百分比超过错误阈值量
circuit.setOpen()
或 circuit.allowSingleTest()
指定秒数的探测
获取令牌 cmd.ticket = <-circuit.executorPool.Tickets
go 执行命令 任何一个先执行完就归还ticket
go 执行超时验证 任何一个先执行完就归还ticket
结构体嵌套结构:
type CircuitBreaker struct {\tName string\topen bool\tforceOpen bool\tmutex *sync.RWMutex\topenedOrLastTestedTime int64\texecutorPool *executorPool\tmetrics *metricExchange}
执行池结构type executorPool struct {\tName string\tMetrics *poolMetrics\tMax int\tTickets chan *struct{}}
用以10秒以熔断核心数据收集type poolMetrics struct {\tMutex *sync.RWMutex\tUpdates chan poolMetricsUpdate\tName string\tMaxActiveRequests *rolling.Number\t//最大活动请求\tExecuted *rolling.Number\t//执行统计}
type Number struct {\tBuckets map[int64]*numberBucket\tMutex *sync.RWMutex}
func (r *Number) Increment(i float64) {\tif i == 0 {\t\treturn\t}\tr.Mutex.Lock()\tdefer r.Mutex.Unlock()\tb := r.getCurrentBucket()\tb.Value += i\tr.removeOldBuckets()}
//指标交换器type metricExchange struct {\tName string\tUpdates chan *commandExecution\tMutex *sync.RWMutex\tmetricCollectors []metricCollector.MetricCollector}
用以10秒内统计多种指标DefaultMetricCollector{ successes *rolling.Number failures *rolling.Number timeouts *rolling.Number}
类库与项目整合思路很清晰
实现熔断器配置
添加熔断中间件
https://cloud.tencent.com/developer/article/1454740
http://127.0.0.1:2001/hystrix.stream
http://192.168.3.4:8080/hystrix/
http://192.168.3.4:8080/hystrix/monitor?stream=http%3A%2F%2F192.168.3.4%3A2001%2Fhystrix.stream&title=stream
效果展示
docker run -d -p 8080:9002 --name hystrix-dashboard mlabouardy/hystrix-dashboard:latest
网关实战
核心结构体与配置
权限认证
客户端ip白名单验证
原理
示例
白名单 配置
添加中间件
jwt验证
配置
数据统计
websocket支持测试
ModifyResponse必须要加Upgrade验证判断
构建自测环境
http://127.0.0.1:2002/websocket
https支持测试
1、证书生成步骤 可跳过
2、启动下游机器 demo/proxy/reverse_proxy_http2/real_server
3、设置TLSClientConfig的特殊设置,如果不考虑证书可以跳过即可
https测试
创建证书文件和私钥
openssl genrsa -out server.pem 2048
openssl req -new -x509 -key server.pem -out server.crt -days 3650
curl -k 'https://127.0.0.1:3002/'
grpc无法被正常代理
grpc代理
tcp代理支持
tcp代理原理
原理图
实现步骤
构建一个tcp服务器
1、监听服务
2、获取连接请求
3、构建新连接对象并设置超时时间及keepalive
4、设置方法退出时连接关闭
5、调用回调方法
构建一个tcp代理
1、代理实现回调方法结构
2、连接下游服务
3、设置退出时关闭连接
4、一边读数据一边写数据
tcp服务器与tcp代理结合,完整中间件配置,实现基于负载均衡的代理
grpc透明代理支持
grpc基本知识科普
grpc是基于http2协议的
grpc示例demo
http2到grpc数据是如何转换的? 代码分析之
grpc实现透明反向代理难点有哪些?
http与grpc协议不同
grpc本身需要proto结构体才能做转换操作
grpc是双向数据流
grpc代理原理
原理图:要体现原始字节与proto关系
构建一个codec解码器
构建支持原始字节、支持proto的解码器
如果拿到的是原始字节,则不需要解码,如果不是原始字节则需要通过proto转换一下
构建输出方法,设置到server参数中
构建回调函数
构建一个下游连接器
构建一个回调类
获取上游数据写入到下游
获取下游头及数据写入到上游
封装输出方法,设置到server参数中
负载均衡拓展服务发现
分布式数据库
主要当前主流:etcd、zookeeper
测试功能
brew services start zookeeper
构建服务发现
认识zookeeper核心功能
认识基本功能
增、删、改、查 api
监听子节点变化
为啥主节点一定能要是持久化节点?
代码演示
监听节点内容变化
zk: version conflict问题
与负载均衡中间件整合
观察者模式优点:逻辑解耦,后期可以拓展N种配置更新方法
1、subject主题对象是模块配置
2、负载均衡器是观察者
3、主题与观察者绑定
功能代码测试
结合步骤:
1、新增构建负载均衡的方法
2、下层负载算法实现 Update
0 条评论
回复 删除
下一页