• 分布式文件快速搜索技术细节分析(开源/并行)


    系列文章

    1.分布式文件快速搜索(多计算机并行/多种算法)

    2.分布式文件快速搜索的设计与实现(开源/分布式计算/并行)

    3.分布式文件快速搜索-技术细节分析(开源/并行)

     

    前言

     在上一篇文章中,对分布式文件快速搜索的设计与实现进行了说明。今天,将对具体的实现细节进行分析。

    文件的检索

    • 文件获取

      1). 一般地,用Directory.GetDirectories()加上SearchOption.AllDirectories来获取某个的目录下的所有文件(包括任意层子文件)。但在这里会采用自行递归获取,每获取一层目录的文件,都会预先根据SearchTypes条件(如文件大小、文件名、修改时间、属性等)来碰撞。具体参看WorkV7FindFileRunner.FindLocal方法。

      2). 相比递归获取文件列表,我们可以直接读取物理磁盘的MFT(Master File Table)主文件表,这样不需要逐个目录递归,直接顺序获取所有文件夹和文件记录,速度可以比递归快10倍以上。在Windows NT便引入的NTFS文件系统,拥有USN Journal(文件日志),每个文件的变化(添加、修改、删除、更名等)都会被记录,在通过MFT获取所有文件后,每次运行,只需要判断一下系统的变化并记录便可,无需重新扫描整个磁盘。

    • 哈希获取

      在使用SearchTypes条件过滤完成后,使用MD5CryptoServiceProvider来获取MD5哈希值。当然,你可以使用SHA1CryptoServiceProvider计算哈希值,如果你觉得MD5不可靠,具体参看WorkUtils.HashMD5File。


      实际的哈希获取,会使用缓存。缓存的实现使用快速二进制序列化,原理是判断缓存数据库是否存在一样的文件信息(文件名、大小和修改时间),如果匹配,则返回已经存在的哈希值,否则就获取新的哈希值。具体参看LocalHashStorage。

    文件的匹配/比较

     文件的匹配有3种方式:完全一致、包含以及全文索引。

    1. 完全一致

      完全一致,直接使用哈希值比较。

    2. 包含

      适用于运行时搜索,判断文本文件中包含的内容。目前直接使用File.ReadAllText(file).IndexOf(keyword, StringComparison.InvariantCultureIgnoreCase)来判断,可能遇到的问题应该是文件太大导致内存溢出。

    3. 全文索引

      可索引文件的全文内容会自动缓存,支持自定义扩展接口IFileContentIndex,目前内置了微软的IFilter实现。具体参看LocalFileContentIndexStorage。

    并行计算的处理

    实现

    因为不是.NET3.5/4,没有PPL,只能模拟并行,来源参看分布式文件快速搜索v7.0(多计算机并行/多种算法)。原理是使用ThreadPool.QueueUserWorkItem各个任务,使用ManualResetEvent记住每个任务的状态,并用WaitHandle.WaitAll等待所有任务完成。具体参看ParallelProcessor.ExecuteParallel。

    ExecuteParallel
    public static void ExecuteParallel(IParallelWorker[] methods)
            {
                
    if (methods.Length > 0)
                {
                    
    // Initialize the reset events to keep track of completed threads
                    ManualResetEvent[] resetEvents = new ManualResetEvent[methods.Length];

                    
    // Launch each method in it's own thread
                    for (int i = 0; i < methods.Length; i++)
                    {
                        resetEvents[i] 
    = new ManualResetEvent(false);
                        ThreadPool.QueueUserWorkItem(
    new WaitCallback(delegate(object index)
                        {
                            
    int methodIndex = (int)index;

                            
    // Execute the method
                            methods[methodIndex].Run();

                            
    // Tell the calling thread that we're done
                            resetEvents[methodIndex].Set();
                        }), i);
                    }

                    
    // Wait for all threads to execute
                    WaitHandle.WaitAll(resetEvents);
                }
            }

    线程安全

    在多线程的环境中,最常见的问题是线程安全。.NET 2.0中,Dictionary是不安全的,我用网上封装的SynchronizedDictionary,当然,我们还可以使用折腾箱子的HashTable。在.NET 4.0中,你可以使用ConcurrentDictionary。

    除了集合,在访问FileStream等对象的情况,你都必须注意保证线程安全,否则数据会跟实际预想不一致。

    任务切分

    并行计算最关键是如何切分任务。在上一篇文章中我已经简略地说明,实际的逻辑比较复杂。首先,根据要搜索的文件组和最大任务数进行切分,在每个任务中,判断文件夹是否为远程文件夹,如果是,则使用分布式搜索,否则本地搜索,具体参看WorkV7FindFileRunner。

    在上述所有文件夹搜索任务都完成后,聚合搜索结果,再根据网络/本地切分任务。对于本地文件夹,则判断是否为同一个物理磁盘,如果是,则动态使用并行计算以实现加速。具体参看WorkV7.Find()。

    具体参看上一篇文章的流程图、WorkV7FindFileRunner(第一次根据文件大小、名称等过滤)和WorkV7FindResultRunner(根据文件属性过滤后再根据匹配方式搜索)。

    分布式的实现

    这是本程序的最大特点。分布式的原理就是在各个节点部署一个监听程序,多个节点组合成一个grid,在监听的同时,也可以作为客户端发送请求。

    数据的传输

    本程序没有使用XML作为数据载体,而是使用了自定义的格式:文件头+数据体(如文件内容等),文件头包括了命令等信息。整个内容可选压缩算法,每个数据包在最后自动添加结束标记,以便在TCP中识别。

    协议

    分布式文件快速搜索自定义了协议接口,内置了对HTTP、TCP和FTP的支持,你可以自由添加各种协议。每种网络连接,都会使用异步处理,避免堵塞请求。

    譬如:

    c:\temp\abc.txt
    \\lancomputer\temp\abc.txtt
    http://1.2.3.4:88/foo/abc.txt
    tcp://1.2.3.4:55/foo/abc.txt
    ftp://1.2.3.4/foo/abc.txt
    pop3://1.2.3.4:101/foo/abc.txt
    skydrive://foo/abc.txt
    dropbox://foo/abc.txt
    AmazonS3://foo/abc.txt
    flicker://foo/abc.jpg
    facebook://foo/abc.jpg

    1. HTTP

      每个数据包都使用POST方式,在可选压缩后把数据写入Request.GetRequestStream,具体参看HTTPFileWorkProvider。在服务器端,使用HttpListener监听,在获得每个HttpListenerRequest后,调用基类(BaseManager)的ProcessRequest处理Request.InputStream,具体参看WorkV7HTTPManager

      HttpListener有点诡异,使用fooListener.Prefixes.Add()来定义监听的路径。在调用HttpListener之前,你需要使用HttpListener.IsSupported判断一下你的操作系统是否支持:必须XP SP2或以上、Win2003、Vista、08、Win7。HttpListener本身不支持SSL,但你可以httpcfg.exe来配置,之前我参看的是一篇英文的文章,现在一下子找不到,大家就凑合用中文的吧:配置HttpListener侦听SSL连接详解

    2. TCP

      每个具体的操作,会先使用AsynchronousClient进行连接,服务器使用AsynchronousSocketListener进行监听,在Received事件处理客户端发送来的请求,具体参看TCPFileWorkProvider和WorkV7TCPManager。

    3. FTP

      使用.NET内置的FTPWebRequest,具体参看FTPFileWorkProvider。

     

    大数据的传输

    在下一个大版本中,将会提供对文件同步的支持。文件传输,有很多现成的软件可以做参考。我的设想是:把文件动态切分成多个小块以减少内存的占用,标记之,成功就记录一个,失败/断开后下次传输,则可以断点续传。当然,一样可选压缩算法,以提高传输性能。

    代码下载

    点击这里下载:Filio.zip

    项目地址

    本项目已经在http://filio.codeplex.com/ 开源

  • 相关阅读:
    Google Analytics的Gif请求数据解读
    还原当年创业:屌丝逆袭后的华丽转身 (zz)
    减去脂肪,轻身上阵 (zz)
    离婚,感谢 (转载)
    delphi如何调用.NET webservice
    如何修改远程登陆3389端口
    软件中的2038问题讨论
    去掉cxgrid上面的分组的灰色栏
    从MDF文件恢复Sql Server2000数据库
    CxGrid的一些使用方法
  • 原文地址:https://www.cnblogs.com/unruledboy/p/FilioTechDetails.html
Copyright © 2020-2023  润新知