不做大哥好多年 不做大哥好多年
首页
  • MySQL
  • Redis
  • Elasticsearch
  • Kafka
  • Etcd
  • MongoDB
  • TiDB
  • RabbitMQ
  • 01.Python
  • 02.GO
  • 03.Java
  • 04.业务问题
  • 05.关键技术
  • 06.项目常识
  • 10.计算机基础
  • Docker
  • K8S
  • 容器原理
  • Istio
  • 01.GO基础
  • 02.面向对象
  • 03.并发编程
  • 04.常用库
  • 05.数据库操作
  • 06.Beego框架
  • 07.Beego商城
  • 08.GIN框架
  • 09.GIN论坛
  • 10.微服务
  • 01.Python基础
  • 02.Python模块
  • 03.Django
  • 04.Flask
  • 05.SYL
  • 06.Celery
  • 10.微服务
  • 01.Java基础
  • 02.面向对象
  • 03.Java进阶
  • 04.Web基础
  • 05.Spring框架
  • 100.微服务
  • 数据结构
  • 算法基础
  • 算法题分类
  • 前置知识
  • PyTorch
  • Langchain
  • Linux基础
  • Linux高级
  • Nginx
  • KeepAlive
  • ansible
  • zabbix
  • Shell
  • Linux内核

逍遥子

不做大哥好多年
首页
  • MySQL
  • Redis
  • Elasticsearch
  • Kafka
  • Etcd
  • MongoDB
  • TiDB
  • RabbitMQ
  • 01.Python
  • 02.GO
  • 03.Java
  • 04.业务问题
  • 05.关键技术
  • 06.项目常识
  • 10.计算机基础
  • Docker
  • K8S
  • 容器原理
  • Istio
  • 01.GO基础
  • 02.面向对象
  • 03.并发编程
  • 04.常用库
  • 05.数据库操作
  • 06.Beego框架
  • 07.Beego商城
  • 08.GIN框架
  • 09.GIN论坛
  • 10.微服务
  • 01.Python基础
  • 02.Python模块
  • 03.Django
  • 04.Flask
  • 05.SYL
  • 06.Celery
  • 10.微服务
  • 01.Java基础
  • 02.面向对象
  • 03.Java进阶
  • 04.Web基础
  • 05.Spring框架
  • 100.微服务
  • 数据结构
  • 算法基础
  • 算法题分类
  • 前置知识
  • PyTorch
  • Langchain
  • Linux基础
  • Linux高级
  • Nginx
  • KeepAlive
  • ansible
  • zabbix
  • Shell
  • Linux内核
  • Python

  • GO

  • Java

  • 业务问题

  • 关键技术

    • 01.接口幂等
    • 02.支付中分布式事务
    • 03.限流
    • 04.断点续传
    • 05.连接池设计
      • 01.连接池设计
        • 1、客户端连接池 作用
        • 2、服务端连接池 使用场景
        • 3、gRPC中的连接池实现
        • 1)创建连接池结构
        • 2)初始化连接池
        • 3)获取连接
        • 4)归还连接
  • 项目常识

  • 计算机基础

  • 区块链

  • 常识
  • 关键技术
xiaonaiqiang
2024-09-24
目录

05.连接池设计

连接池通过复用现有连接减少创建和关闭连接的开销,提升系统性能

客户端连接池在频繁通信场景下尤为重要,避免每次请求都创建新连接,通过长连接和多路复用支持并发,降低网络资源消耗

连接池的设计包含文件分块、状态记录、超时机制等,确保多连接并发处理

服务端的数据库连接池、线程池等场景也使用池化管理资源

gRPC中,连接池可以提高请求并发性,并通过负载均衡和并发安全机制分散负载

# 01.连接池设计

  • 连接池通常是在客户端设置的,而不是服务端
  • 客户端需要频繁与服务端通信时,连接池可以减少连接的建立和断开,提升性能

# 1、客户端连接池 作用

  • 减少连接建立的开销:

    • 每次建立新的网络连接(例如TCP连接)都会有一定的开销,涉及到握手、认证等过程
    • 通过连接池,客户端可以复用已有的连接,避免每次请求都重新创建连接
  • 提高并发性能:

    • 当客户端需要频繁发送请求时,连接池可以提供多个连接并行使用,减少单个连接的瓶颈
    • 例如,在gRPC中,一个grpc.ClientConn对象可以支持多路复用(即在一个连接上并发发送多个请求)
    • 但在超大规模并发场景下,单个连接可能仍会成为性能瓶颈
    • 因此可以使用连接池创建多个ClientConn对象以分散负载
  • 保持连接的长久性:

    • 连接池可以保持长连接,避免因频繁的连接断开和重连带来的性能问题
    • 长时间不使用的连接可以通过池管理自动释放或健康检查
  • 复用连接:

    • 客户端发起的多个请求可以复用池中的连接,而不是每次都新建连接
    • 从而节省资源,减少不必要的TCP/IP握手以及SSL握手(如果有)的开销

# 2、服务端连接池 使用场景

  • 虽然连接池主要应用在客户端,但在某些情况下,服务端也会涉及到连接池的概念
  • 数据库连接池:

    • 服务端通常会和数据库打交道,为了提高访问数据库的效率,服务端会使用数据库连接池来复用与数据库的连接
  • 线程/协程池:

    • 虽然不完全是“连接池”,但服务端为了处理高并发请求
    • 可能会使用线程池或协程池来复用计算资源,从而高效处理多个并发请求
  • 反向代理:

    • 在服务端层面,也可以使用连接池来管理反向代理服务与后端微服务之间的连接
    • 例如,负载均衡器或网关可以为与后端服务之间的连接维护一个连接池,避免频繁创建新的连接

# 3、gRPC中的连接池实现

  • gRPC是基于HTTP/2协议的高性能RPC框架,天然支持长连接、多路复用等特性
  • Go中的gRPC客户端库通过grpc.Dial()函数来创建一个客户端连接
  • 通常建议使用长连接,但在某些场景下,创建多个连接并通过连接池复用是必要的,尤其是在并发请求量较大时
  • 长连接复用:gRPC基于HTTP/2协议,支持长连接和多路复用通过连接池可以避免频繁创建和销毁连接,减少资源消耗
  • 并发安全:通过Go中的sync.Mutex或者chan机制确保连接的获取和归还过程是并发安全的
  • 连接负载均衡:连接池能够在多个连接之间均匀分发请求,避免单个连接过载

# 1)创建连接池结构

  • 创建一个结构体保存连接池信息,包括连接的数组(或其他并发安全的数据结构)、连接池的最大容量、空闲连接队列等
type GRPCPool struct {
    mu         sync.Mutex
    clients    []*grpc.ClientConn
    maxClients int
    idle       chan *grpc.ClientConn
}
1
2
3
4
5
6

# 2)初始化连接池

  • 初始化连接池时,创建一定数量的gRPC连接,并将它们加入池中
// NewGRPCPool 创建并初始化一个 gRPC 连接池
// 参数:
// - maxClients: 连接池中最多的连接数
// - target: gRPC 服务器的地址,例如 "localhost:50051"
// 返回值:
// - GRPCPool 结构体的指针
// - error 如果创建连接失败,返回错误
func NewGRPCPool(maxClients int, target string) (*GRPCPool, error) {
    // 创建一个 GRPCPool 结构体,并初始化其字段
    pool := &GRPCPool{
        maxClients: maxClients,                              // 设定连接池中最大连接数
        clients:    make([]*grpc.ClientConn, 0, maxClients), // 初始化用于保存连接的切片
        idle:       make(chan *grpc.ClientConn, maxClients), // 创建一个用于存放空闲连接的通道(缓冲大小为 maxClients)
    }

    // 循环创建 maxClients 个 gRPC 连接
    for i := 0; i < maxClients; i++ {
        // 通过 grpc.Dial() 连接到 target 指定的 gRPC 服务端
        // target 是 gRPC 服务器的地址(例如 localhost:50051)
        conn, err := grpc.Dial(target, grpc.WithInsecure()) // 创建 gRPC 客户端连接
        if err != nil {
            return nil, err // 如果连接失败,返回错误
        }

        // 将创建的连接添加到 clients 切片
        pool.clients = append(pool.clients, conn)
        
        // 将连接放入 idle 通道,表示该连接现在是空闲的
        pool.idle <- conn
    }

    return pool, nil
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 3)获取连接

从连接池中获取可用的gRPC连接

func (p *GRPCPool) Get() (*grpc.ClientConn, error) {
    select {
    case conn := <-p.idle:
        return conn, nil
    default:
        return nil, errors.New("no available gRPC connections")
    }
}
1
2
3
4
5
6
7
8

# 4)归还连接

  • 请求处理完后,将连接归还到池中
func (p *GRPCPool) Put(conn *grpc.ClientConn) {
    p.idle <- conn
}
1
2
3
上次更新: 2025/2/19 16:42:39
04.断点续传
01.DDD领域驱动设计

← 04.断点续传 01.DDD领域驱动设计→

最近更新
01
05.快递Agent智能体
06-04
02
200.AI Agent核心概念
06-04
03
105.Agent智能体梳理
06-04
更多文章>
Theme by Vdoing | Copyright © 2019-2025 逍遥子 技术博客 京ICP备2021005373号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式