关于udp:线上-udp-客户端请求服务端客户端句柄泄漏问题
本题别离从如下三个方面来分享: 问题形容<!----> 自定义连接池的编写<!----> common_pool 的应用问题形容线上有一个业务,某个通服务告诉 udp 客户端通过向 udp 服务端(某个硬件设施)发送 udp 包来进行用户上线操作 当同时有大量的申请打到 udp 服务端的时候,udp 服务端的回包可能会在网络环境中丢包,(udp 是不牢靠的)导致 udp 客户端不能及时的收到 udp 服务端的回包,在短时间内,udp 客户端的句柄又没有失去复用或者开释,没有收到回包的句柄就始终阻塞在那里,最终导致句柄透露 那么能够如何解决呢? 增大客户端的句柄数<!----> 应用连接池并且在读取服务端响应数据时加上超时工夫显然,第一个解决形式治标不治本,改大句柄数,当申请质变大的时候,依然会呈现句柄透露的状况 第二种形式绝对靠谱很多 首先,咱们将发送 udp 包给服务端后,期待读取服务端的回包时,设置超时工夫,超时后读取失败,开释或者偿还句柄<!----> 保护一个外部的连接池,缩小每一次创立句柄耗费的资源和工夫,应用的时候从池子外面获取句柄,应用结束之后再偿还句柄自定义连接池的编写 customer_pool那么对于连接池,咱们实际上是能够本人来进行造轮子的,仅用于学习,理论应用的话,天然还是会去应用通过公众考研过的公共开源库,咱们能够来根本的剖析和钻研一下一个连接池须要有些什么? 创立池子,敞开池子,池子的敞开状态<!----> 从池子中获取连贯,偿还连贯,销毁以后连贯<!----> 池子中能包容的最大连接数,最小连接数,以后连接数<!----> 依据以后理论的连接数来对池子进行扩容和缩容<!----> 池子中创立连贯的函数具体实现当然,咱们本人来领会一下连接池以及演示上述 udp 的 demo,咱们仅实现如下几个简略性能作为演示 创立池子,池子的敞开状态<!----> 从池子中获取连贯,偿还连贯<!----> 池子中能包容的最大连接数,最小连接数,以后连接数<!----> 池子中创立连贯的函数具体实现对于池子中具体链接的销毁,池子的敞开,池子的扩缩容,以及其余高级应用,xdm 能够进行扩大 customer_pool demo自定义连接池,实际上咱们是应用 chan 通道来进行实现,具体源码能够查看:https://github.com/qingconglaixueit/customer_pool/blob/master/customer_pool/pool.go 定义连接池 MyConnPool 数据结构,和创立连接池MyConnPool 构造中的 sync.Mutex 次要是用于管制多协程中 非 pool 成员的其余成员的互斥,咱们晓得 chan 外部是有锁进行管制的 获取对象的具体实现从池子中获取对象,如果获取不到则默认查看以后的池子状态是否能够创立新的连贯<!----> 若能够,则间接创立连贯,返回对象<!----> 此处在进行池子成员的变动时,须要加锁进行管制func (conn *MyConnPool) GetObject() (interface{}, error) { return conn.getObject()}func (conn *MyConnPool) getObject() (interface{}, error) { if conn.isClosed { return nil, errors.New("pool is closed") } // 从通道外面读,如果通道外面没有则新建一个 select { case object := <-conn.pool: return object, nil default: } // 校验以后的连接数是否大于最大连接数,若是,则还是须要从 pool 中取 // 此时应用 mutex 次要是为了锁 MyConnPool 的非通道的其余成员 conn.Lock() if conn.currentConn >= conn.maxConn { object := <-conn.pool conn.Unlock() return object, nil } // 逻辑走到此处须要新建对象放到 pool 中 object, err := conn.connFun() if err != nil { conn.Unlock() return nil, fmt.Errorf("create conn error : %+v", err) } // 以后 pool 已有连接数+1 conn.currentConn++ conn.Unlock() return object, nil}开释对象的具体实现应用结束对象之后,须要偿还<!----> ...