fastdfs分布式文件系统之TrackerServer连接池实现

非常感谢  http://blog.csdn.net/Mr_Smile2014/article/details/52441824

FastDFS 技术学习,更多知识请访问https://www.itkc8.com

公司使用fastdfs文件系统来存储文件和图片,为了避免每个系统都直接通过客户端直接访问fastdfs文件系统,所以我们做了一个

 

dubbo服务。要实现图片上传、下载的服务或工程直接调用dubbo接口就可以了。为了提高性能对fastdfs文件系统TrackerServer写了个

连接池,同时写了空闲连接是否可用的监测类。

下面对连接池的具体实现作介绍。

 

连接池类

 

 

实现配置文件的读取、初始化各项参数、创建默认的TrackerServer数、空闲连接获取、释放繁忙连接及删除不可用的连接;

 

[java] view plain copy

  1. package com.xxxx.fastdfs.pool;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.UUID;  
  5. import java.util.concurrent.LinkedBlockingQueue;  
  6. import java.util.concurrent.TimeUnit;  
  7.   
  8. import org.csource.fastdfs.ClientGlobal;  
  9. import org.csource.fastdfs.TrackerClient;  
  10. import org.csource.fastdfs.TrackerServer;  
  11. import org.slf4j.Logger;  
  12. import org.slf4j.LoggerFactory;  
  13.   
  14. import com.xxxx.common.AppException;  
  15. import com.xxxx.fastdfs.exception.ERRORS;  
  16.   
  17. /** 
  18.  *  
  19.  * @ClassName: ConnectionPool 
  20.  * @Description: fastdfs连接池 
  21.  * @author mr_smile2014 [email protected] 
  22.  * @date 2015年10月26日 下午3:36:02 
  23.  *  
  24.  */  
  25. public class ConnectionPool {  
  26.     private static final Logger LOGGER = LoggerFactory  
  27.             .getLogger(ConnectionPool.class);  
  28.     /** 空闲的连接池 */  
  29.     private LinkedBlockingQueue idleConnectionPool = null;  
  30.     /** 连接池默认最小连接数 */  
  31.     private long minPoolSize = 10;  
  32.     /** 连接池默认最大连接数 */  
  33.     private long maxPoolSize = 30;  
  34.     /** 当前创建的连接数 */  
  35.     private volatile long nowPoolSize = 0;  
  36.     /** 默认等待时间(单位:秒) */  
  37.     private long waitTimes = 200;  
  38.     /** fastdfs客户端创建连接默认1次 */  
  39.     private static final int COUNT = 1;  
  40.   
  41.     /** 
  42.      * 默认构造方法 
  43.      */  
  44.     public ConnectionPool(long minPoolSize, long maxPoolSize, long waitTimes) {  
  45.         String logId = UUID.randomUUID().toString();  
  46.         LOGGER.info("[线程池构造方法(ConnectionPool)][" + logId  
  47.                 + "][默认参数:minPoolSize=" + minPoolSize + ",maxPoolSize="  
  48.                 + maxPoolSize + ",waitTimes=" + waitTimes + "]");  
  49.         this.minPoolSize = minPoolSize;  
  50.         this.maxPoolSize = maxPoolSize;  
  51.         this.waitTimes = waitTimes;  
  52.         /** 初始化连接池 */  
  53.         poolInit(logId);  
  54.         /** 注册心跳 */  
  55.         HeartBeat beat = new HeartBeat(this);  
  56.         beat.beat();  
  57.     }  
  58.   
  59.     /** 
  60.      *  
  61.      * @Description: 连接池初始化 (在加载当前ConnectionPool时执行) 1).加载配置文件 2).空闲连接池初始化; 
  62.      *               3).创建最小连接数的连接,并放入到空闲连接池; 
  63.      *  
  64.      */  
  65.     private void poolInit(String logId) {  
  66.         try {  
  67.             /** 加载配置文件 */  
  68.             initClientGlobal();  
  69.             /** 初始化空闲连接池 */  
  70.             idleConnectionPool = new LinkedBlockingQueue();  
  71.             /** 往线程池中添加默认大小的线程 */  
  72.             for (int i = 0; i < minPoolSize; i++) {  
  73.                 createTrackerServer(logId, COUNT);  
  74.             }  
  75.         } catch (Exception e) {  
  76.             LOGGER.error("[FASTDFS初始化(init)--异常][" + logId + "][异常:{}]", e);  
  77.         }  
  78.     }  
  79.   
  80.     /** 
  81.      *  
  82.      * @Description: 创建TrackerServer,并放入空闲连接池 
  83.      *  
  84.      */  
  85.     public void createTrackerServer(String logId, int flag) {  
  86.   
  87.         LOGGER.info("[创建TrackerServer(createTrackerServer)][" + logId + "]");  
  88.         TrackerServer trackerServer = null;  
  89.   
  90.         try {  
  91.   
  92.             TrackerClient trackerClient = new TrackerClient();  
  93.             trackerServer = trackerClient.getConnection();  
  94.             while (trackerServer == null && flag < 5) {  
  95.                 LOGGER.info("[创建TrackerServer(createTrackerServer)][" + logId  
  96.                         + "][第" + flag + "次重建]");  
  97.                 flag++;  
  98.                 initClientGlobal();  
  99.                 trackerServer = trackerClient.getConnection();  
  100.             }  
  101.             org.csource.fastdfs.ProtoCommon.activeTest(trackerServer  
  102.                     .getSocket());  
  103.             idleConnectionPool.add(trackerServer);  
  104.             /** 同一时间只允许一个线程对nowPoolSize操作 **/  
  105.             synchronized (this) {  
  106.                 nowPoolSize++;  
  107.             }  
  108.   
  109.         } catch (Exception e) {  
  110.   
  111.             LOGGER.error("[创建TrackerServer(createTrackerServer)][" + logId  
  112.                     + "][异常:{}]", e);  
  113.   
  114.         } finally {  
  115.   
  116.             if (trackerServer != null) {  
  117.                 try {  
  118.                     trackerServer.close();  
  119.                 } catch (Exception e) {  
  120.                     LOGGER.error("[创建TrackerServer(createTrackerServer)--关闭trackerServer异常]["  
  121.                             + logId + "][异常:{}]", e);  
  122.                 }  
  123.             }  
  124.   
  125.         }  
  126.     }  
  127.   
  128.     /** 
  129.      *  
  130.      * @Description: 获取空闲连接 1).在空闲池(idleConnectionPool)中弹出一个连接; 
  131.      *               2).把该连接放入忙碌池(busyConnectionPool)中; 3).返回 connection 
  132.      *               4).如果没有idle connection, 等待 wait_time秒, and check again 
  133.      *  
  134.      * @throws AppException 
  135.      *  
  136.      */  
  137.     public TrackerServer checkout(String logId) throws AppException {  
  138.   
  139.         LOGGER.info("[获取空闲连接(checkout)][" + logId + "]");  
  140.         TrackerServer trackerServer = idleConnectionPool.poll();  
  141.   
  142.         if (trackerServer == null) {  
  143.   
  144.             if (nowPoolSize < maxPoolSize) {  
  145.                 createTrackerServer(logId, COUNT);  
  146.                 try {  
  147.                     trackerServer = idleConnectionPool.poll(waitTimes,  
  148.                             TimeUnit.SECONDS);  
  149.                 } catch (Exception e) {  
  150.                     LOGGER.error("[获取空闲连接(checkout)-error][" + logId  
  151.                             + "][error:获取连接超时:{}]",e);  
  152.                     throw ERRORS.WAIT_IDLECONNECTION_TIMEOUT.ERROR();  
  153.                 }  
  154.             }  
  155.             if (trackerServer == null) {  
  156.                 LOGGER.error("[获取空闲连接(checkout)-error][" + logId  
  157.                         + "][error:获取连接超时(" + waitTimes + "s)]");  
  158.                 throw ERRORS.WAIT_IDLECONNECTION_TIMEOUT.ERROR();  
  159.             }  
  160.   
  161.         }  
  162.         LOGGER.info("[获取空闲连接(checkout)][" + logId + "][获取空闲连接成功]");  
  163.         return trackerServer;  
  164.   
  165.     }  
  166.   
  167.     /** 
  168.      *  
  169.      * @Description: 释放繁忙连接 1.如果空闲池的连接小于最小连接值,就把当前连接放入idleConnectionPool; 
  170.      *               2.如果空闲池的连接等于或大于最小连接值,就把当前释放连接丢弃; 
  171.      *  
  172.      * @param client1 
  173.      *            需释放的连接对象 
  174.      *  
  175.      */  
  176.   
  177.     public void checkin(TrackerServer trackerServer, String logId) {  
  178.   
  179.         LOGGER.info("[释放当前连接(checkin)][" + logId + "][prams:" + trackerServer  
  180.                 + "] ");  
  181.         if (trackerServer != null) {  
  182.             if (idleConnectionPool.size() < minPoolSize) {  
  183.                 idleConnectionPool.add(trackerServer);  
  184.             } else {  
  185.                 synchronized (this) {  
  186.                     if (nowPoolSize != 0) {  
  187.                         nowPoolSize--;  
  188.                     }  
  189.                 }  
  190.             }  
  191.         }  
  192.   
  193.     }  
  194.   
  195.     /** 
  196.      *  
  197.      * @Description: 删除不可用的连接,并把当前连接数减一(调用过程中trackerServer报异常,调用一般在finally中) 
  198.      * @param trackerServer 
  199.      *  
  200.      */  
  201.     public void drop(TrackerServer trackerServer, String logId) {  
  202.         LOGGER.info("[删除不可用连接方法(drop)][" + logId + "][parms:" + trackerServer  
  203.                 + "] ");  
  204.         if (trackerServer != null) {  
  205.             try {  
  206.                 synchronized (this) {  
  207.                     if (nowPoolSize != 0) {  
  208.                         nowPoolSize--;  
  209.                     }  
  210.                 }  
  211.                 trackerServer.close();  
  212.             } catch (IOException e) {  
  213.                 LOGGER.info("[删除不可用连接方法(drop)--关闭trackerServer异常][" + logId  
  214.                         + "][异常:{}]", e);  
  215.             }  
  216.         }  
  217.     }  
  218.   
  219.     private void initClientGlobal() throws Exception {  
  220.         ClientGlobal.init("fastdfs_client.conf");  
  221.     }  
  222.   
  223.     public LinkedBlockingQueue getIdleConnectionPool() {  
  224.         return idleConnectionPool;  
  225.     }  
  226.   
  227.     public long getMinPoolSize() {  
  228.         return minPoolSize;  
  229.     }  
  230.   
  231.     public void setMinPoolSize(long minPoolSize) {  
  232.         if (minPoolSize != 0) {  
  233.             this.minPoolSize = minPoolSize;  
  234.         }  
  235.     }  
  236.   
  237.     public long getMaxPoolSize() {  
  238.         return maxPoolSize;  
  239.     }  
  240.   
  241.     public void setMaxPoolSize(long maxPoolSize) {  
  242.         if (maxPoolSize != 0) {  
  243.             this.maxPoolSize = maxPoolSize;  
  244.         }  
  245.     }  
  246.   
  247.     public long getWaitTimes() {  
  248.         return waitTimes;  
  249.     }  
  250.   
  251.     public void setWaitTimes(int waitTimes) {  
  252.         if (waitTimes != 0) {  
  253.             this.waitTimes = waitTimes;  
  254.         }  
  255.     }  
  256.   
  257. }  
 

 

连接池定时检测器

 

用于定时检测连接池空闲队列中的连接是否可用,如果不可用将从连接池中移除。

 

[java] view plain copy

  1. package com.xxxx.fastdfs.pool;  
  2.   
  3. import java.util.Timer;  
  4. import java.util.TimerTask;  
  5. import java.util.UUID;  
  6. import java.util.concurrent.LinkedBlockingQueue;  
  7. import java.util.concurrent.TimeUnit;  
  8.   
  9. import org.csource.fastdfs.TrackerServer;  
  10. import org.slf4j.Logger;  
  11. import org.slf4j.LoggerFactory;  
  12.   
  13. /** 
  14.  *  
  15.  * @ClassName: HeartBeat 
  16.  * @Description: 连接池定时器设置 
  17.  * @author mr_smile2014 [email protected] 
  18.  * @date 2015年1月14日 下午2:21:29 
  19.  *  
  20.  */  
  21. public class HeartBeat {  
  22.     private static final Logger LOGGER = LoggerFactory  
  23.             .getLogger(HeartBeat.class);  
  24.     /** fastdfs连接池 */  
  25.     private ConnectionPool pool = null;  
  26.     /** 小时毫秒数 */  
  27.     public static int ahour = 1000 * 60 * 60 * 1;  
  28.     /** 等待时间 */  
  29.     public static int waitTimes = 200;  
  30.   
  31.     public HeartBeat(ConnectionPool pool) {  
  32.         this.pool = pool;  
  33.     }  
  34.   
  35.     /** 
  36.      *  
  37.      * @Description: 定时执行任务,检测当前的空闲连接是否可用,如果不可用将从连接池中移除 
  38.      *  
  39.      */  
  40.     public void beat() {  
  41.         LOGGER.info("[心跳任务方法(beat)]");  
  42.         TimerTask task = new TimerTask() {  
  43.             @Override  
  44.             public void run() {  
  45.                 String logId = UUID.randomUUID().toString();  
  46.                 LOGGER.info("[心跳任务方法(beat)]["  
  47.                         + logId  
  48.                         + "][Description:对idleConnectionPool中的TrackerServer进行监测]");  
  49.                 LinkedBlockingQueue idleConnectionPool = pool  
  50.                         .getIdleConnectionPool();  
  51.                 TrackerServer ts = null;  
  52.                 for (int i = 0; i < idleConnectionPool.size(); i++) {  
  53.                     try {  
  54.                         ts = idleConnectionPool.poll(waitTimes,  
  55.                                 TimeUnit.SECONDS);  
  56.                         if (ts != null) {  
  57.                             org.csource.fastdfs.ProtoCommon.activeTest(ts  
  58.                                     .getSocket());  
  59.                             idleConnectionPool.add(ts);  
  60.                         } else {  
  61.                             /** 代表已经没有空闲长连接 */  
  62.                             break;  
  63.                         }  
  64.                     } catch (Exception e) {  
  65.                         /** 发生异常,要删除,进行重建 */  
  66.                         LOGGER.error("[心跳任务方法(beat)][" + logId  
  67.                                 + "][异常:当前连接已不可用将进行重新获取连接]");  
  68.                         pool.drop(ts, logId);  
  69.                     }  
  70.                 }  
  71.             }  
  72.         };  
  73.         Timer timer = new Timer();  
  74.         timer.schedule(task, ahour, ahour);  
  75.     }  
  76.   
  77. }  
 

 

连接池调用

 

 

[java] view plain copy

  1. /** 获取fastdfs服务器连接 */  
  2.   
  3.         trackerServer = connectionPool.checkout(logId);  
  4.         StorageServer storageServer = null;  
  5.         StorageClient1 client1 = new StorageClient1(trackerServer,  
  6.                 storageServer);  
  7.   
  8.         /** 以文件字节的方式上传 */  
  9.         ..........................  
  10.   
  11.         /** 上传完毕及时释放连接 */  
  12.         connectionPool.checkin(trackerServer, logId);  
 

 

连接池的使用最好是再写一个工具类,在工具类当中进行连接池的初始化及上传、下载、删除功能的实现。把工具类配置到spring配置文件中,

生成对应的bean,其它用到的地方直接调用该bean的对应方法就可以了。工具类的实现将在下一篇文章中分享。

FastDFS 技术学习,更多知识请访问https://www.itkc8.com

你可能感兴趣的:(FastDFS)