fastDFS遇到的并发问题

fastDFS遇到的并发问题recv cmd: 0 is not correct, expect cmd: 100

此贴是我对一篇帖子FastDFS并发会有bug,其实我也不太信?进行的一些测试和我自己也发现的相关问题与解决方案。

最开始我也按照帖子进行了测试,结果发现确实存在并发问题(下面代码改为单线程是木有问题的)。以下列出我尝试的几种情况:

先列出我进行测试的有main函数的FastConcurrence类:

[java] view plain copy
  1. public class FastConcurrence {  
  2.     private static int poolSize=2;//定义线程个数  
  3.     public static void main(String[] args) throws InterruptedException {  
  4.         latchTest();  
  5.     }  
  6.     private static void latchTest() throws InterruptedException {  
  7.            final CountDownLatch start = new CountDownLatch(1);  
  8.            final CountDownLatch end = new CountDownLatch(poolSize);  
  9.            ExecutorService exce = Executors.newFixedThreadPool(poolSize);  
  10.            for (int i = 0; i < poolSize; i++) {  
  11.                Runnable run = new Runnable() {  
  12.                    @Override  
  13.                    public void run() {  
  14.                        try {  
  15.                            start.await();  
  16.                            testLoad();  
  17.                        } catch (Exception e) {  
  18.                            e.printStackTrace();  
  19.                        } finally {  
  20.                            end.countDown();  
  21.                        }  
  22.                    }  
  23.                };  
  24.                exce.submit(run);  
  25.            }  
  26.            start.countDown();  
  27.            end.await();  
  28.            exce.shutdown();  
  29.        }  
  30.       
  31. private static void testLoad() throws Exception {  
  32.      String filePath="D:\\fastDFS\\ques.png";  
  33.      File content=new File(filePath);  
  34.      TestFileManager test=new TestFileManager();  
  35.         FastDFSFile file =test.getFastFile(content,"png");  
  36.     for (int i=0;i<10;i++){                                                                                  FileManager.upload(file);//里面封装了我转文件为byte[]和上传文件方法storageClient.upload_file   
  37.            }  
  38.            System.out.println("完成一个线程!");  
  39.     }   
  40. }  

①把trackerClient,trackerServer,storageServer,storageClient设为全局变量。在类加载的时候,就进行了初始化,关键代码如下:

[java] view plain copy
  1. private static TrackerClient  trackerClient;    
  2. private static TrackerServer  trackerServer;  
  3. private static StorageServer  storageServer;  
  4. private static StorageClient  storageClient;  
  5.   
  6. static {   
  7.     try {  
  8.   // 初始化文件资源    
  9.   ClientGlobal.init("C:\\Users\\jianbo\\Downloads\\FastDFS\\conf\\client.conf");  
  10.         trackerClient = new TrackerClient();    
  11.         trackerServer = trackerClient.getConnection();    
  12.         //有并发问题,所以勿重用storageClient  
  13.         storageClient = new StorageClient(trackerServer, storageServer);  
  14.     } catch (Exception e) {    
  15.         logger.error(logger,  e);  
  16.     }    
  17. }   
果不其然报错了:
[java] view plain copy
  1. java.net.SocketException: socket closed  
  2.     at java.net.SocketInputStream.socketRead0(Native Method)  
  3.     at java.net.SocketInputStream.socketRead(Unknown Source)  
  4.     at java.net.SocketInputStream.read(Unknown Source)  
  5.     at java.net.SocketInputStream.read(Unknown Source)  
  6.     at org.csource.fastdfs.ProtoCommon.recvPackage(ProtoCommon.java:263)  
  7.     at org.csource.fastdfs.TrackerClient.getStoreStorage(TrackerClient.java:143)  
  8.     at org.csource.fastdfs.StorageClient.newWritableStorageConnection(StorageClient.java:1938)  
  9.     at org.csource.fastdfs.StorageClient.do_upload_file(StorageClient.java:703)  
  10.     at org.csource.fastdfs.StorageClient.upload_file(StorageClient.java:208)  
  11.     at org.csource.fastdfs.StorageClient.upload_file(StorageClient.java:226)  
  12.     at fastdfs.FileManager.upload(FileManager.java:76)  
  13.     at fastdfs.FastConcurrence.testLoad(FastConcurrence.java:48)  
  14.     at fastdfs.FastConcurrence.access$0(FastConcurrence.java:42)  
  15.     at fastdfs.FastConcurrence$1.run(FastConcurrence.java:27)  
  16.     at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)  
  17.     at java.util.concurrent.FutureTask.run(Unknown Source)  
  18.     at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)  
  19.     at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)  
  20.     at java.lang.Thread.run(Unknown Source)  
  21. java.io.IOException: recv cmd: 0 is not correct, expect cmd: 100  
  22.     at org.csource.fastdfs.ProtoCommon.recvHeader(ProtoCommon.java:219)  
  23.     at org.csource.fastdfs.ProtoCommon.recvPackage(ProtoCommon.java:250)  
  24.     at org.csource.fastdfs.TrackerClient.getStoreStorage(TrackerClient.java:143)  
  25.     at org.csource.fastdfs.StorageClient.newWritableStorageConnection(StorageClient.java:1938)  
  26.     at org.csource.fastdfs.StorageClient.do_upload_file(StorageClient.java:703)  
  27.     at org.csource.fastdfs.StorageClient.upload_file(StorageClient.java:208)  
  28.     at org.csource.fastdfs.StorageClient.upload_file(StorageClient.java:226)  
  29.     at fastdfs.FileManager.upload(FileManager.java:76)  
  30.     at fastdfs.FastConcurrence.testLoad(FastConcurrence.java:48)  
  31.     at fastdfs.FastConcurrence.access$0(FastConcurrence.java:42)  
  32.     at fastdfs.FastConcurrence$1.run(FastConcurrence.java:27)  
  33.     at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)  
  34.     at java.util.concurrent.FutureTask.run(Unknown Source)  
  35.     at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)  
  36.     at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)  
  37.     at java.lang.Thread.run(Unknown Source)  
②我在调用storageClient.upload_file(byte[] file_buff, String file_ext_name, NameValuePair[] meta_list)前一句再storageClient = new StorageClient(trackerServer, storageServer); 

关键代码如下:

[java] view plain copy
  1. public static String[] upload(FastDFSFile file) {  
  2.    try {  
  3.      storageClient = new StorageClient(trackerServer, storageServer);//新加的  
  4.      uploadResults = storageClient.upload_file(file.getContent(), file.getExt(), meta_list);  
  5.    } catch (Exception e) {  
  6.      logger.error("Exception when uploadind the file:" + file.getName(), e);  
  7.    }  
  8.    //省略一部分代码  
  9.    return uploadResults;  
  10. }  
好了,出现了和上面①一样的问题。

我发现,其实这样本质没有变,还是去改了全局storageClient 。应该new个新的,所以产生了③。

我在调用storageClient.upload_file(byte[] file_buff, String file_ext_name, NameValuePair[] meta_list)前一句再StorageClient storageClient = new StorageClient(trackerServer, storageServer); 就是原帖最后说明的解决办法。

[java] view plain copy
  1. public static String[] upload(FastDFSFile file) {  
  2.    try {  
  3.      StorageClient storageClient = new StorageClient(trackerServer, storageServer);//新加的  
  4.      uploadResults = storageClient.upload_file(file.getContent(), file.getExt(), meta_list);  
  5.    } catch (Exception e) {  
  6.      logger.error("Exception when uploadind the file:" + file.getName(), e);  
  7.    }  
  8.    //省略一部分代码  
  9.    return uploadResults;  
  10. }  
我还是报错,和前面一样的异常。原因还没有来得及找,不过我采用锁是没有问题的。

④在调用方法的时候采用锁就能解决。例如这个方法我加了锁就没有问题了。

[java] view plain copy
  1. private synchronized static void testLoad() throws Exception {  
  2.            String filePath="D:\\fastDFS\\ques.png";  
  3.            File content=new File(filePath);  
  4.            TestFileManager test=new TestFileManager();  
  5.            FastDFSFile file =test.getFastFile(content,"png");  
  6.            for (int i=0;i<10;i++){  
  7.                FileManager.upload(file);  
  8.            }  
  9.            System.out.println("完成一个线程!");  
  10.         }   

一路顺畅。不过③为什么报错了,我还要研究下。

补:对于③我找到问题了。

源码下载下来,然后我就查StorageClient类,发现在do_upload_file方法中,有一段代码:

[java] view plain copy
  1. bUploadSlave = ((group_name != null && group_name.length() > 0) &&   
  2.                         (master_filename != null && master_filename.length() > 0) &&  
  3.                         (prefix_name != null));  
  4.         if (bUploadSlave)  
  5.         {  
  6.             bNewConnection = this.newUpdatableStorageConnection(group_name, master_filename);  
  7.         }  
  8.         else  
  9.         {  
  10.             bNewConnection = this.newWritableStorageConnection(group_name);  
  11.         }  
其中的
[java] view plain copy
  1. this.newWritableStorageConnection(group_name);  
具体方法是:
[java] view plain copy
  1. protected boolean newWritableStorageConnection(String group_name) throws IOException, MyException  
  2.     {  
  3.         if (this.storageServer != null)  
  4.         {  
  5.             return false;  
  6.         }  
  7.         else  
  8.         {  
  9.             TrackerClient tracker = new TrackerClient();  
  10.         this.storageServer = tracker.getStoreStorage(this.trackerServer, group_name);  
  11.         if (this.storageServer == null)  
  12.         {  
  13.             throw new MyException("getStoreStorage fail, errno code: " + tracker.getErrorCode());  
  14.         }  
  15.         return true;  
  16.         }  
  17.   }  
而这个方法里面的

[java] view plain copy
  1. this.storageServer = tracker.getStoreStorage(this.trackerServer, group_name);  
找进去发现每次trackerServer用完了,就关闭连接了。

trackerServer.close();

所以后面线程都被关闭了,就报IO异常,只要在方法③中new StorageClient前面加一句:

[java] view plain copy
  1. TrackerServer trackerServer = trackerClient.getConnection();  
就解决问题了。





[java] view plain copy
  1. this.storageServer = tracker.getStoreStorage(this.trackerServer, group_name);  
文章标签: fastDFS 并发 多线程
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值