反响代理实现原理

前言

之前接触的代理是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/

你可能感兴趣的:(反响代理实现原理)