上一篇文章已经就 fastdfs安装完毕并可以应用,大部分业务已经可以使用。但是在写入实时性要求很高的情况下,需要进行优化。
主要涉及2个方面:
1、系统优化,优化IO
达到内存多少百分比时,刷入IO磁盘 pdflush
原值:echo 10 > /proc/sys/vm/dirty_background_ratio
echo 1 > /proc/sys/vm/dirty_background_ratio
同上,非pdflush
原值: echo 20 > /proc/sys/vm/dirty_ratio
echo 1 > /proc/sys/vm/dirty_ratio
多久后算脏页,毫秒
原值 echo 3000 > /proc/sys/vm/dirty_expire_centisecs
echo 100 > /proc/sys/vm/dirty_expire_centisecs
---------------------
作者:一杯米酒
来源:CSDN
原文:https://blog.csdn.net/yangyongdehao30/article/details/78427298
版权声明:本文为博主原创文章,转载请附上博文链接!
2、代码优化
因为淘宝的fastdfs本身是异步的,当要求既存既取的时候,会有取不到内容的情况(脏页的大小和刷新频率决定了存储时间,然而每个文件实时存储,则极大浪费CPU),所以这里写了一个缓存代理,在写入时缓存中会进行同步存储文件流数据,在取值的时候,如果nginx发现为空,则去缓存再查找一次。
架构如下
若需使用可以下载 https://github.com/yangyongdehao30/fastdfs-plus.git
部署fastdfs-http项目,注意指定membercache服务,java上传文件使用fastdfs-client-java驱动包(需部署memcache服务一台)nginx server标签中做如下配置
location ^~ /group1/M00 {
alias /data/fdfs/data;
index index.html index.htm;
try_files $uri $uri/ /memcache?http://$server_addr/$uri;
}
location ^~ /group1/M01 {
alias /data/fdfs1/data;
index index.html index.htm;
try_files $uri $uri/ /memcache?http://$server_addr/$uri;
}
location /memcache {
proxy_pass http://10.0.2.230:12120/getFile?url=$query_string;
}
以下是本人基于fastdfs-client-java驱动包封装的util,仅供参考
package com.jinhuhang.risk.util;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.aspectj.util.FileUtil;
import org.csource.common.MyException;
import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.ServerInfo;
import org.csource.fastdfs.StorageClient1;
import org.csource.fastdfs.StorageServer;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import com.alibaba.dubbo.common.threadpool.support.fixed.FixedThreadPool;
import com.alibaba.fastjson.JSONObject;
import com.jinhuhang.risk.common.Constant;
/**
* @project risk-common
* @author yy
* @date 2017年7月11日 上午10:32:31
* @description TODO fdfs文件存储 工具类
* @tag 指定配置文件地址:配置 fdfs.confpath 属性
*/
public class FDFSUtil {
private static TrackerClient trackerClient = null;
private static TrackerServer trackerServer = null;
private static StorageServer storageServer = null;
//使用StorageClient1进行上传
private static StorageClient1 storageClient1 = null;
static {
if(StringUtils.isEmpty(Constant.getConfig("fdfs.confpath")))
new FDFSUtil().init("fdfs_client.conf");
else
new FDFSUtil().init(Constant.getConfig("fdfs.confpath"));
}
public void init(String config)
{
try {
ClientGlobal.init(config);
trackerClient = new TrackerClient();
trackerServer = trackerClient.getConnection();
storageServer = trackerClient.getStoreStorage(trackerServer);
storageClient1 = new StorageClient1(trackerServer, storageServer);
} catch (Exception e) {
throw new RuntimeException("初始化FDFS出错:",e);
}
}
/**
* @title uploadFile
* @description 按字节上传文件
* @author yy
* @date 2017年7月11日 上午10:38:51
* @param file_buff 字节数
* @param file_ext_name 后缀名
* @return
* @throws Exception
* @return String
*/
public static String uploadFile(byte[] file_buff, String file_ext_name) throws Exception {
String path="http://"+storageServer.getInetSocketAddress().getHostName()+"/"+storageClient1.upload_file1(file_buff, file_ext_name, null);
Thread.sleep(1500);
return path;
}
/**
* @title deleteFile
* @description 删除文件
* @author yy
* @date 2017年7月11日 上午10:54:38
* @param remote_filename
* @return
* @throws Exception
* @return boolean
*/
private static boolean delete_file(String remote_filename) throws Exception
{
String group_name=remote_filename.substring(0, remote_filename.indexOf("/"));
remote_filename = remote_filename.substring(remote_filename.indexOf("/")+1);
int i = storageClient1.delete_file(group_name, remote_filename);
if(i==0)
return true;
return false;
}
/**
* @title uploadFile
* @description 按名称上传文件
* @author yy
* @date 2017年7月11日 上午10:42:13
* @param local_filename 文件名
* @param file_ext_name 后缀名
* @return
* @throws Exception
* @return String
*/
public static String uploadFile(String local_filename, String file_ext_name) {
try {
return storageClient1.upload_file1(local_filename, file_ext_name, null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @title downloadFileAsString
* @description 下载文件 ,返回默认编码 格式的字符串
* @author yy
* @date 2017年7月11日 上午10:43:39
* @param remote_filename 文件名
* @return
* @throws Exception
* @return String
*/
public static String downloadString(String remote_filename)
{
return HttpUrlPost.sendGet(remote_filename,"");
}
public static byte[] downloadFile(String remote_filename)
{
return HttpUrlPost.sendGet(remote_filename,"").getBytes();
}
/**
* @title uploadBytes
* @description 按字节流上传
* @author yy
* @date 2017年7月12日 下午2:22:13
* @param bytes
* @return
* @return String
*/
public static String uploadBytes(byte[] bytes) {
try {
return uploadFile(bytes, "");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @title uploadFile
* @description 存储字符串
* @author yy
* @date 2017年7月11日 上午10:48:30
* @param stringFile
* @return
* @return String
*/
public static String uploadString(String stringContent) {
try {
return uploadFile(stringContent.getBytes(), "");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String uploadString(String stringContent,String suffix) {
try {
return uploadFile(stringContent.getBytes(), suffix);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @title uploadFile
* @description 存储多个字符串,要么全部成功,要么全部失败
* @author yy
* @date 2017年7月11日 上午10:48:30
* @param stringFile
* @return
* @return List<FilePath>
*/
public static List<String> uploadStrings(String...stringContent) {
List<String> list = new ArrayList<String>();
try {
for (String string : stringContent) {
list.add(uploadFile(string.getBytes(), ""));
}
return list;
} catch (Exception e) {
try {//删掉已经成功上传的
for (String string : list) {
delete_file(string);
}
} catch (Exception e2) {
// TODO: handle exception
}
throw new RuntimeException(e);
}
}
/**
* @title deleteFile
* @description 删除文件
* @author yy
* @date 2017年7月11日 上午11:07:05
* @param remote_filename
* @return
* @return boolean
*/
public static boolean deleteFile(String remote_filename)
{
try {
String group_name=remote_filename.substring(0, remote_filename.indexOf("/"));
remote_filename = remote_filename.substring(remote_filename.indexOf("/")+1);
int i = storageClient1.delete_file(group_name, remote_filename);
if(i==0)
return true;
} catch (Exception e) {
throw new RuntimeException(e);
}
return false;
}
public static void main(String[] args) {
System.out.println("开始运行...");
//检测FDFS
try {
new FDFSUtil().init("D:/fdfs_client.conf");
String s = "";
String path = FDFSUtil.uploadFile(s.getBytes(), "txt");
System.out.println(path);
} catch (Exception e) {
e.printStackTrace();
}
// boolean b=FDFSUtil.deleteFile("group1/M00/02/1A/CgACpVms18OAeoOjAAAoe0alckw.ym_con");
// FixedThreadPool fp=new FixedThreadPool()
/*for (int i = 0; i < 1; i++) {
//运行main时,注释掉 static代码块
new FDFSUtil().init("D:\\fdfs_client.conf");
try {
boolean b = FDFSUtil.delete_file("group1/M01/00/35/wKgBP1ma04GAHdgNAAAff5K7hls6629483");
System.out.println(b);
}catch (Exception e){
e.printStackTrace();
}
// System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS"));
// String uploads="[{\"phone\":\"17602151396\",\"name\":\"测试号\"},{\"phone\":\"13569936336\",\"name\":\"测试二号\"}]";
// String str=FDFSNewUtil.uploadString(uploads);
// System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS")+"str>"+str);
// String reStr=FDFSNewUtil.downloadString(str);
// System.out.println("reStr:"+reStr);
// String filePath =FDFSUtil.uploadFile("C:\\Users\\yangyong\\Desktop\\newtxt.txt", "txt");
// System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS")+"filePath>"+filePath);
// List<String> list=FDFSNewUtil.uploadStrings("{\"a\":\"av\",\"b\":\"bv\",\"c\":\"cv\"}","{\"a\":\"av\",\"b\":\"bv\",\"c\":\"cv\"}");
// System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS")+"list>"+list.toArray().toString());
String reStr=FDFSNewUtil.downloadString(str);
System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS")+"reStr>"+reStr);
byte[] bs=FDFSNewUtil.downloadFile(str);
System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS")+"bs>"+bs);
// System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS")+"delete str>"+FDFSNewUtil.deleteFile(str));
System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS")+"delete filePath>"+FDFSNewUtil.deleteFile(filePath));
// for (String s : list) {
// System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS")+"delete list.s>"+FDFSNewUtil.deleteFile(s));
// }
}*/
}
}