grpc 连接池实现

9 篇文章 0 订阅
3 篇文章 0 订阅

一,首先,grpc有没有必要实现连接池?
测试及分析见前文:记一次web请求量上不去的排查记录,及grpc client请求优化
二,如果我们确实需要实现自己的连接池,代码如下:
1.首先引入apache的池化包

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.5.0</version>
        </dependency>

2.实现自己的连接池

import cn.sdwan.major.service.impl.HomePageServiceImpl;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ChannelStatePool {
    private static final Logger log = LoggerFactory.getLogger(ChannelStatePool.class);

    private static GenericObjectPool<ChannelStateClient> objectPool=null;
    static {
        // 连接池的配置
        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
        // 池中的最大连接数
        poolConfig.setMaxTotal(5);
        // 最少的空闲连接数
        poolConfig.setMinIdle(1);
        // 最多的空闲连接数
        poolConfig.setMaxIdle(4);
        // 当连接池资源耗尽时,调用者最大阻塞的时间,超时时抛出异常 单位:毫秒数
        poolConfig.setMaxWaitMillis(5000);
        // 连接池存放池化对象方式,true放在空闲队列最前面,false放在空闲队列最后
        poolConfig.setLifo(true);
        // 连接空闲的最小时间,达到此值后空闲连接可能会被移除,默认即为30分钟
        poolConfig.setMinEvictableIdleTimeMillis(1000L * 60L * 30L);
        // 连接耗尽时是否阻塞,默认为true
        poolConfig.setBlockWhenExhausted(true);
        // 连接池创建
        objectPool = new GenericObjectPool<>(new ChannelStateFactory(), poolConfig);
    }

    /**
     * 从连接池获取对象
     */
    public static ChannelStateClient borrowObject(){
        log.debug("borrowObject");
        try {
            ChannelStateClient clientSingle = objectPool.borrowObject();
            log.debug("总创建线程数,{}",objectPool.getCreatedCount());
            return clientSingle;
        } catch (Exception e) {
            e.printStackTrace();
        }
        //连接池失败则主动创建
        return createClient();
    }
    /**
     * 还回连接池获取的对象
     */
    public static void returnObject(ChannelStateClient channelStateClient){
        log.debug("returnObject");
        try {
            objectPool.returnObject(channelStateClient);
            log.debug("总创建线程数,{}",objectPool.getCreatedCount());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 当连接池异常,则主动创建对象
     */
    private static ChannelStateClient createClient(){
        return new ChannelStateClient("channel", 8080);
    }

    /**
     * 执行器
     * @param workCallBack 主要服务内容
     */
    public static Runnable execute(WorkCallBack<ChannelStateClient> workCallBack){
        return () -> {
            ChannelStateClient client = borrowObject();
            try {
                workCallBack.callback(client);
            } finally {
                /** 将连接对象返回给连接池 */
                objectPool.returnObject(client);
            }
        };
    }
}

3.创建一个需要池化对象的工厂类

import cn.sdwan.major.service.impl.HomePageServiceImpl;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ChannelStatePool {
    private static final Logger log = LoggerFactory.getLogger(ChannelStatePool.class);

    private static GenericObjectPool<ChannelStateClient> objectPool=null;
    static {
        // 连接池的配置
        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
        // 池中的最大连接数
        poolConfig.setMaxTotal(5);
        // 最少的空闲连接数
        poolConfig.setMinIdle(1);
        // 最多的空闲连接数
        poolConfig.setMaxIdle(4);
        // 当连接池资源耗尽时,调用者最大阻塞的时间,超时时抛出异常 单位:毫秒数
        poolConfig.setMaxWaitMillis(5000);
        // 连接池存放池化对象方式,true放在空闲队列最前面,false放在空闲队列最后
        poolConfig.setLifo(true);
        // 连接空闲的最小时间,达到此值后空闲连接可能会被移除,默认即为30分钟
        poolConfig.setMinEvictableIdleTimeMillis(1000L * 60L * 30L);
        // 连接耗尽时是否阻塞,默认为true
        poolConfig.setBlockWhenExhausted(true);
        // 连接池创建
        objectPool = new GenericObjectPool<>(new ChannelStateFactory(), poolConfig);
    }

    /**
     * 从连接池获取对象
     */
    public static ChannelStateClient borrowObject(){
        log.debug("borrowObject");
        try {
            ChannelStateClient clientSingle = objectPool.borrowObject();
            log.debug("总创建线程数,{}",objectPool.getCreatedCount());
            return clientSingle;
        } catch (Exception e) {
            e.printStackTrace();
        }
        //连接池失败则主动创建
        return createClient();
    }
    /**
     * 还回连接池获取的对象
     */
    public static void returnObject(ChannelStateClient channelStateClient){
        log.debug("returnObject");
        try {
            objectPool.returnObject(channelStateClient);
            log.debug("总创建线程数,{}",objectPool.getCreatedCount());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 当连接池异常,则主动创建对象
     */
    private static ChannelStateClient createClient(){
        return new ChannelStateClient("channel", 8080);
    }

4.使用该连接池,并还回该对象

//借用
ChannelStateClient client=ChannelStatePool.borrowObject();
//使用
Obeject  res = client.getObj();
//归还
ChannelStatePool.returnObject(client);

完成

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 C# 中实现 GRPC连接,可以按照以下步骤进行: 1. 安装 .NET Core SDK 和 GRPC 工具 首先需要安装 .NET Core SDK 和 GRPC 工具。可以在官网下载安装包,也可以使用命令行工具进行安装。 2. 创建 GRPC 服务和客户端 在 Visual Studio 中创建一个 GRPC 服务和客户端。可以使用 Visual Studio 的模板进行创建,也可以使用命令行工具创建。 3. 实现连接逻辑 在服务端和客户端代码中,实现连接逻辑。可以使用 GRPC 提供的流式调用接口,或者使用自定义的长连接逻辑。 4. 启动 GRPC 服务和客户端 在服务端代码中启动 GRPC 服务,等待客户端连接。在客户端代码中连接 GRPC 服务,并发送请求。 下面是一个简单的示例代码,实现GRPC连接的功能: 服务端代码: ```csharp public class MyService : MyService.MyServiceBase { public override async Task<MyResponse> LongConnect(IAsyncStreamReader<MyRequest> requestStream, ServerCallContext context) { while (await requestStream.MoveNext()) { var request = requestStream.Current; Console.WriteLine($"Received request: {request.Message}"); } return new MyResponse { Message = "Long connection closed." }; } } class Program { static void Main(string[] args) { var server = new Server { Services = { MyService.BindService(new MyService()) }, Ports = { new ServerPort("localhost", 50051, ServerCredentials.Insecure) } }; server.Start(); Console.WriteLine("Server started."); Console.ReadLine(); server.ShutdownAsync().Wait(); } } ``` 客户端代码: ```csharp class Program { static async Task Main(string[] args) { var channel = new Channel("localhost", 50051, ChannelCredentials.Insecure); var client = new MyService.MyServiceClient(channel); var cts = new CancellationTokenSource(); var call = client.LongConnect(cancellationToken: cts.Token); try { while (!call.IsCompleted) { Console.Write("Enter message to send: "); var message = Console.ReadLine(); await call.RequestStream.WriteAsync(new MyRequest { Message = message }); await Task.Delay(1000); } } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { cts.Cancel(); await call.RequestStream.CompleteAsync(); } Console.WriteLine("Long connection closed."); Console.ReadLine(); } } ``` 在上面的示例中,服务端实现了一个名为 LongConnect 的长连接方法,客户端通过调用该方法建立长连接,并在循环中发送请求。服务端在收到客户端请求后,将请求内容输出到控制台。客户端在每秒钟发送一次请求,并等待用户输入。当用户输入 exit 命令时,客户端结束循环,并关闭连接

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值