本文主要是介绍FastDfs优化---解决RuntimeException: Unable to borrow buffer from pool问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- 目录索引
- FastDfs优化
- 1.目前问题
- 2.解决思路
- 3.Fastdfs的默认连接数量
- 4.yml配置FastDfs参数
目录索引
Fastdfs—开源地址
Fastdfs—为什么选择使用Fastdfs和nginx?(附架构图)
Fastdfs—基本介绍和底层模型详解
Fastdfs—安装fastdfs和nginx
Fastdfs—安装常见报错处理大全
FastDfs优化
使用fastDfs中碰见了一个RuntimeException: Unable to borrow buffer from pool运行时异常:不能从池中获取缓存
,在解决了这个异常的过程中通过FastDfs的源码了解到了FastDfs的初始化过程。这个bug就可以通过在FastDfs初始化的时候,设置pool池的相关数据即可解决。
这里将里面单个文件连接与pool池默认参数列举出来,我们可以根据自己的需求设置相应的yml进行优化FastDfs。
//fast单个参数private int soTimeout;//读取时间private int connectTimeout;//超时连接时间//fast下pool的参数public static final int FDFS_MAX_TOTAL = 50;//连接池最大连接数50public static final boolean FDFS_TEST_WHILE_IDLE = true;public static final boolean FDFS_BLOCK_WHEN_EXHAUSTED = true;//当缓存池耗尽是否阻塞,默认为true false直接报异常,true阻塞直到超时public static final long FDFS_MAX_WAIT_MILLIS = 100L;//连接耗尽最大等待时间 毫秒,超时抛出异常public static final long FDFS_MIN_EVICTABLE_IDLETIME_MILLIS = 180000L;//休眠时间超过该值则视为过期时间public static final long FDFS_TIME_BETWEEN_EVICTION_RUNS_MILLIS = 60000L;//60秒进行一次后台清理public static final int FDFS_NUM_TESTS_PEREVICTION_RUN = -1;//清理时检查所有线程
1.目前问题
在项目进行测试时,有多个人进行了文件的上传下载操作。而操作的是同一个fastdfs,就会出现以下异常
**异常报错代码
/*** 下载文件** @param fileUrl 文件URL* @return 文件字节* @throws IOException*/public byte[] downloadFileByte(String fileUrl) throws IOException {String group = fileUrl.substring(0, fileUrl.indexOf("/"));String path = fileUrl.substring(fileUrl.indexOf("/") + 1);-----这一行开始报错DownloadByteArray downloadByteArray = new DownloadByteArray();byte[] bytes = fastFileStorageClient.downloadFile(group, path, downloadByteArray);return bytes;}
2.解决思路
1.报错原因翻译
RuntimeException: Unable to borrow buffer from pool
运行时异常:不能从池中获取缓存
2.异常中来看是因为 fastdfs中客户端的连接池已经用完,导致了没有可用的连接。
3.那么我们查看fastdfs中默认的连接数量是多少,设置fastdfs的默认连接数量即可
3.Fastdfs的默认连接数量
1.在我们方法中调用了DefaultGenerateStorageClient
类中downloadFile
方法
public <T> T downloadFile(String groupName, String path, long fileOffset, long fileSize, DownloadCallback<T> callback) {StorageNodeInfo client = this.trackerClient.getFetchStorage(groupName, path);StorageDownloadCommand<T> command = new StorageDownloadCommand(groupName, path, fileOffset, fileSize, callback);return this.connectionManager.executeFdfsCmd(client.getInetSocketAddress(), command);//进行fastdfs连接下载}
2.ConnectionManager
进行连接Pool操作 -------------真正报错原因
我们查看代码可以知道报错是因为 FdfsConnectionPool这个自动注入时失败,从而导致这个异常。那么我们等下直接去查看这个类是如何进行初始化的。
//自动注入FdfsConnectionPool,而FdfsConnectionPool具有初始值。@Autowiredprivate FdfsConnectionPool pool;public <T> T executeFdfsCmd(InetSocketAddress address, FdfsCommand<T> command) {Connection conn = this.getConnection(address);return this.execute(address, conn, command);}protected Connection getConnection(InetSocketAddress address) {Connection conn = null;try {//这一段 就是我们报错出现的原因,进行FdfsConnectionPool类自动注入。conn = (Connection)this.pool.borrowObject(address);return conn;} catch (FdfsException var4) {throw var4;} catch (Exception var5) {LOGGER.error("Unable to borrow buffer from pool", var5);throw new RuntimeException("Unable to borrow buffer from pool", var5);}}
3.FdfsConnectionPool
连接池的初始化设置
@Autowiredpublic FdfsConnectionPool(KeyedPooledObjectFactory<InetSocketAddress, Connection> factory, GenericKeyedObjectPoolConfig config) {super(factory, config);}
构造方法中有两个参数 KeyedPooledObjectFactory
GenericKeyedObjectPoolConfig
这两个参数决定了fastdfs的两个值
3.1首先我们查看KeyedPooledObjectFactory
`这个参数
因为这是一个接口,我们直接进入它的实现类中。而实现类中有一个PooledConnectionFactory
就是fast的相关初始化设置。
- 设置读取时间
- 设置超时连接时间
@Component
@ConfigurationProperties(prefix = "fdfs"
)
public class PooledConnectionFactory extends BaseKeyedPooledObjectFactory<InetSocketAddress, Connection> {private int soTimeout;//读取时间private int connectTimeout;//超时连接时间
}
所以我们一般会在yml中进行配置
fdfs:
#单位 毫秒soTimeout: 15000 # 读取时间connectTimeout: 15000 # 超时连接时间
3.2在GenericKeyedObjectPoolConfig
连接池初始化内容
因为都是自动注入,而该类上并没有@Componen
注解所以这个是一个父类。我们直接进入它的子类中,而我们直接针对里面对应的参数设置我们想要的值
@Component
@ConfigurationProperties(prefix = "fdfs.pool"
)
public class ConnectionPoolConfig extends GenericKeyedObjectPoolConfig {public static final int FDFS_MAX_TOTAL = 50;//连接池最大连接数50public static final boolean FDFS_TEST_WHILE_IDLE = true;public static final boolean FDFS_BLOCK_WHEN_EXHAUSTED = true;//当缓存池耗尽是否阻塞,默认为true false直接报异常,true阻塞直到超时public static final long FDFS_MAX_WAIT_MILLIS = 100L;//连接耗尽最大等待时间 毫秒,超时抛出异常public static final long FDFS_MIN_EVICTABLE_IDLETIME_MILLIS = 180000L;//休眠时间超过该值则视为过期时间public static final long FDFS_TIME_BETWEEN_EVICTION_RUNS_MILLIS = 60000L;//60秒进行一次后台清理public static final int FDFS_NUM_TESTS_PEREVICTION_RUN = -1;//清理时检查所有线程public ConnectionPoolConfig() {this.setMaxTotal(50);//设置连接最大数this.setTestWhileIdle(true);//空闲时检查有效性this.setBlockWhenExhausted(true);//连接耗尽是否阻塞this.setMaxWaitMillis(100L);//获取连接最大等待时间,超过报错this.setMinEvictableIdleTimeMillis(180000L);//休眠时间超过该值则视为过期时间this.setTimeBetweenEvictionRunsMillis(60000L);//60秒进行一次后台清理this.setNumTestsPerEvictionRun(-1);//清理时检查所有线程this.setJmxNameBase("com.github.tobato.fastdfs.conn:type=FdfsConnectionPool");this.setJmxNamePrefix("fdfsPool");}
}
从该类就看得出fastdfs默认的连接池配置,我们针对性的配置fast中内容
#fast-dfs
fdfs:pool:max-total: 200 # 连接池最大数量max-total-per-key: 50 # 单个tracker最大连接数max-wait-millis: 5000 # 连接耗尽最大等待时间 毫秒
4.yml配置FastDfs参数
fdfs:soTimeout: 15000connectTimeout: 15000pool:max-total: 200 # 连接池最大数量max-total-per-key: 50 # 单个tracker最大连接数max-wait-millis: 5000 # 连接耗尽最大等待时间 毫秒
设置过后就再也没有出现过这个异常
这篇关于FastDfs优化---解决RuntimeException: Unable to borrow buffer from pool问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!