前言
之前接触的代理是sofa-mosn这种,它client端连接到mosn后,mosn将数据包转发到后端。其中
1)mosn到后端服务器有个连接池,连接是可以复用的
2)mosn会对数据包进行解包
3)支持请求数据(不是连接请求)的负载均衡
tcp负载均衡
最近接触到TCP层的负载均衡,Proxy只能实现连接的负载均衡,即后端有两个机器,第一个连接会将所有数据发送到S1,第二个连接会转发到S2。相当于client连接proxy后,proxy会创建一个到server的connection。
为什么不能复用连接?
1)proxy不知道client发送的数据内容,也不知道client什么时候发送完。如果proxy到server的连接不是独享的,会导致包错乱。
实现
下面以https://github.com/yyyar/gobetween
为例解释一下。
server.go
# client到proxy的连接
clientConn := ctx.Conn
# 负载均衡选取后端节点,拿到的是服务器的信息,不是连接
backend, err := this.scheduler.TakeBackend(ctx)
# 创建proxy到server的连接
if this.cfg.BackendsTls != nil {
backendConn, err = tls.DialWithDialer(&net.Dialer{
Timeout: utils.ParseDurationOrDefault(*this.cfg.BackendConnectionTimeout, 0),
}, "tcp", backend.Address(), this.backendsTlsConfg)
} else {
backendConn, err = net.DialTimeout("tcp", backend.Address(), utils.ParseDurationOrDefault(*this.cfg.BackendConnectionTimeout, 0))
}
# server返回给proxy的数据 转发给 client
cs := proxy(clientConn, backendConn, utils.ParseDurationOrDefault(*this.cfg.BackendIdleTimeout, 0))
# proxy收到client发送过来的数据 转发给server
bs := proxy(backendConn, clientConn, utils.ParseDurationOrDefault(*this.cfg.ClientIdleTimeout, 0))
具体的proxy过程见proxy.go
func Copy(to io.Writer, from io.Reader, ch chan<- core.ReadWriteCount) error {
for {
# 读数据
readN, readErr := from.Read(buf)
if readN > 0 {
#写数据
writeN, writeErr := to.Write(buf[0:readN])
if writeN > 0 {
ch <- core.ReadWriteCount{CountRead: uint(readN), CountWrite: uint(writeN)}
}
}
}
}
参考
https://github.com/darkhelmet/balance
https://kasvith.me/posts/lets-create-a-simple-lb-go/
网友评论