自定义Thrift连接池

来源:互联网 发布:上海租房网站 知乎 编辑:程序博客网 时间:2024/06/01 17:28

自定义Thrift连接池

Thrift作为一个高性能的RPC框架,广泛应用于后端服务的进程间接口调用场景中。对于Java开发者而言,thrift客户端调用框架并没有提供相关的连接池能力进行使用,对于性能要求较高的用户可以自定义Thrift连接池以满足自身的需求,本着不重复造轮子的原则,笔者使用apache commons-pools2实现了一套自定义的Thrift连接池供大家参考。
关于apache commons-pools2的相关知识,大家可以参考这篇博文:http://blog.csdn.net/amon1991/article/details/77110657


1、创建池对象工厂

PooledObjectFactory(池对象工厂)是commons-pools2中的一个概念,用于控制整个池对象的整个生命周期。

在我们的实例中,这个池对象就是TProtocol对象,准确来说,commons-pools2管理的对象其实是TProtocol在池中的封装对象,也就是实例中通过wrap(TProtocol protocol)方法包裹后生成的对象PooledObject,这个封装的对象保有实际被包装对象的复杂的状态信息,这个状态信息在判断对象是否存活,是否可以被销毁时起到了关键作用。下面给出实际的新建Thfift池对象工厂代码,笔者使用的是TMultiplexedProtocol对象,使用其他TProtocol对象的参考这种写法即可。

代码块

public class TProtocolFactory extends BasePooledObjectFactory<TProtocol>{    private final Logger logger = LoggerFactory.getLogger(this.getClass());    private static final int TIMEOUT = 3000000; // 超时时间    private static final int MAX_LENGTH = 1638400000; // 单次最大传输的数据量(1.6G)    public static final String PI_SERVICE = "PiService";    public static final String OPC_SERVICE = "OpcService";    private String host;    private int port;    private boolean keepAlive = true; // 是否持有Thrift连接,不持有则钝化时释放连接    private String sourceType; // PI数据源还是OPC数据源    public TProtocolFactory(String host, int port, boolean keepAlive, String sourceType) {        this.host = host;        this.port = port;        this.keepAlive = keepAlive;        this.sourceType = sourceType;    }    private TProtocolFactory() {    }    /**     * 创建新对象     * @return     * @throws Exception     */    @Override    public TProtocol create() throws Exception {        TSocket tSocket = new TSocket(host, port,TIMEOUT );        TTransport tTransport = new TFramedTransport(tSocket,MAX_LENGTH);        if (null!= tTransport && !tTransport.isOpen()){            tTransport.open();        }        TProtocol protocol = new TCompactProtocol(tTransport);        if (null != sourceType) {            if (sourceType.equals(PI_SERVICE)){                return new TMultiplexedProtocol(protocol,PI_SERVICE);            }else if (sourceType.equals(OPC_SERVICE)){                return new TMultiplexedProtocol(protocol,OPC_SERVICE);            }else {                return  null;            }        }else {            return null;        }    }    /**     * 将对象放入对象池前先包装对象,好让对象池可以管理     * @param protocol     * @return     */    @Override    public PooledObject<TProtocol> wrap(TProtocol protocol) {        return new DefaultPooledObject<>(protocol);    }    /**     * 对象钝化(即:从激活状态转入非激活状态,returnObject时触发)     * @param pooledObject     * @throws TTransportException     */    @Override    public void passivateObject(PooledObject<TProtocol> pooledObject) throws TTransportException {        if (null!= pooledObject.getObject()){            if (!keepAlive) {                pooledObject.getObject().getTransport().flush();                pooledObject.getObject().getTransport().close();            }        }    }    /**     * 对象激活(borrowObject时触发)     * @param pooledObject     * @throws TTransportException     */    @Override    public void activateObject(PooledObject<TProtocol> pooledObject) throws TTransportException {        if (!pooledObject.getObject().getTransport().isOpen()) {            pooledObject.getObject().getTransport().open();        }    }    /**     * 对象销毁(clear时会触发)     * @param pooledObject     * @throws TTransportException     */    @Override    public void destroyObject(PooledObject<TProtocol> pooledObject) throws TTransportException {        if (null!= pooledObject.getObject()){            if (pooledObject.getObject().getTransport().isOpen()) {                pooledObject.getObject().getTransport().flush();                pooledObject.getObject().getTransport().close();            }        }        pooledObject.markAbandoned();    }    /**     * 验证对象的有效性     * @param pooledObject     * @return     */    @Override    public boolean validateObject(PooledObject<TProtocol> pooledObject) {        if (pooledObject.getObject() != null) {            if (pooledObject.getObject().getTransport().isOpen()) {                return true;            }            try {                pooledObject.getObject().getTransport().open();                return true;            } catch (TTransportException e) {                logger.error(e.getMessage());            }        }        return false;    }}

2、创建对象池实例

Object Pool(对象池)是实际管理所有池对象的容器,主要的方法是borrowObject、returnObject,一个是从池中获取对象,另一个是使用完对象后将对象归还到池中,当然,该容器还提供了一些基本的方法用于获取当前存活的对象数,空闲的对象数等信息,这些信息可用于自定义销毁对象策略等实现。

由于笔者的代码中用到了Spring框架,所以外部代码获取连接池实例使用的是Spring容器管理的单例实例。注意,在对象池的使用上,必须保证对象池是线程安全的,否则可能在多线程环境导致对象池维护的数据产生不一致的问题。假设没有使用Spring框架,笔者推介使用一个饿汉模式的单例来维护pool对象即可。

@Componentpublic class OPCTProtocolPool {    @Autowired    private PiDataSourceConf piDataSource;    @Autowired    private ObjectPoolConfig objectPoolConfig;    private ObjectPool<TProtocol> pool;    /**     * 获取 thrift 连接对象池     * @return     */    public ObjectPool<TProtocol> getPool() {        if (pool == null){            GenericObjectPoolConfig poolConfig = objectPoolConfig.getGenericObjectPoolConfig();            // 第一次加载对象池            pool = new GenericObjectPool<>(new TProtocolFactory(piDataSource.getIp(), piDataSource.getPort(), true ,TProtocolFactory.OPC_SERVICE), poolConfig);        }        return pool;    }}

以上代码中,GenericObjectPoolConfig 对象可以设置连接池的参数,比如最大连接数、最大空闲数、超时时间等信息,具体可以参考commons-pools中的通用配置即可。

3、使用对象池使用TProtocol对象

完成上面两步之后,就可以从对象池中非常简单的获取TProtocol对象了,获取对象使用如下代码:

TProtocol protocol = protocolPool.getPool().borrowObject();

使用完对象后,必须使用同一个对象池返回使用的对象,否则这个对象就在进程中失控了:

protocolPool.getPool().returnObject(protocol);
原创粉丝点击