赞
踩
Fastdfs—开源地址
Fastdfs—为什么选择使用Fastdfs和nginx?(附架构图)
Fastdfs—基本介绍和底层模型详解
Fastdfs—安装fastdfs和nginx
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;//连接池最大连接数50
public 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;//清理时检查所有线程
在项目进行测试时,有多个人进行了文件的上传下载操作。而操作的是同一个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;
}
1.报错原因翻译
RuntimeException: Unable to borrow buffer from pool
运行时异常:不能从池中获取缓存
2.异常中来看是因为 fastdfs中客户端的连接池已经用完,导致了没有可用的连接。
3.那么我们查看fastdfs中默认的连接数量是多少,设置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具有初始值。
@Autowired
private 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
连接池的初始化设置
@Autowired
public 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;//连接池最大连接数50
public 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 # 连接耗尽最大等待时间 毫秒
fdfs:
soTimeout: 15000
connectTimeout: 15000
pool:
max-total: 200 # 连接池最大数量
max-total-per-key: 50 # 单个tracker最大连接数
max-wait-millis: 5000 # 连接耗尽最大等待时间 毫秒
设置过后就再也没有出现过这个异常
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。