Squid Coss文件系统技术分析

现在很多公司都使用Squid作为Cache,Alibaba也不例外,这已经不是什么秘密了。Squid的COSS文件系统特别适合小文件的Cache,是很多公司存放小图片Cache的主要手段。

今天翻电脑,找到早期写的一篇技术分析,供同学们参考,欢迎批评指正

Squid COSS技术分析 
1. COSS机制分析 
 1.1. COSS文件结构分析 
 1.2. COSS的配置分析 
 1.3. COSS Relocation机制 
2. COSS实现分析 3
 2.1. Squid FileSystem架构分析 
 2.2. COSS所使用的核心数据结构 
 2.2.1. SwapDir 
 2.2.2. struct _cossinfo 
 2.2.3. cossstripe 
 2.3. 关键流程分析 
 2.3.1. rebuild 
 2.3.2. Cache HIT时访问Object:storeCossOpen 
3. 案例分析 
 3.1. 案例1 
4. 关于使用COSS的建议 

 
1. COSS机制分析
 1.1. COSS文件结构分析
      COSS文件是Squid专门开发的用于高效存储与管理小文件的应用层File System,全称是Cyclic Object Storage System。逻辑上,COSS文件被分为M+N个Stripe。Stripe是逻辑上COSS所使用的存储单元。在物理上,COSS由多个Stripe无缝串连拼凑起来。其中M指Memory形式的Stripe在硬盘上的映射所占的个数(配置项membufs所设置,默认为10个,表示本COSS文件支持10个内存stripe),N表示COSS剩余部分(Disk stripe)所可划分的最大Stripe数目。
  
      逻辑上,COSS文件被形象的比做是一个“6”的样子,N个Disk Stripe组成一个环形,像是“6”的下部分,M个映射到Mem Stripe,像是“6”上面部分。
  
      一个Stripe可以存放一个或多个Object,但每个Object不能跨越两个Stripe。这就决定了Stripe一旦固定,就不能存放比Stripe大的Object;也决定了,Stripe中几乎不可避免的有空间浪费。
  
     此外,COSS文件物理上,将Stripe再分成Block,因此block大小一定要被stripe大小整除。使用Block的作Squid层物理IO接口的原因我想可能主要是:a) 与系统匹配,使利用OS的FileSytem以及物理Disk块的得以优化 b)Squid使用stripe号,以及fileno号来寻址Object,而fileno只有24位,因此,使用的block越大,COSS支持的文件就越大。
  
 1.2. COSS的配置分析
      从squid.conf来看,coss文件的典型配置如下:
      cache_dir coss /data/cache1/coss0 34500 max-size=1000000 block-size=4096 overwrite-percent=50 membufs=10
      其中,34500表示该COSS文件的最大大小是34.5G,max-size表示支持存储的最大Object大小,本质上就是Stripe的大小。Block-size表示每个物理存储块是4k。overwrite-percent表示当前stripe游标与该object原来存放地方的游标(Offset)之前的距离大于50%的整个COSS文件长度时,进行Relocation(文件搬移,后面详细说明),这个overwrite-percent一定要好好理解。
  
 1.3. COSS Relocation机制
       其实上,大家从测试中可以看到,Squid使用COSS时,即使在全Cache HIT的情况下,也会有大量的IO write操作。其根本就在于COSS的relocation机制。
      本质上,Relocation是解决COSS文件的老化淘汰问题而引入的。因为COSS没有LRU或其它老化算法的根本原因是COSS无法实现随意的删除。Relocation是老化的一种变相实现。为什么这么说呢,要先分析一个COSS文件的使用机制。
     上面提到,COSS的Disk Stripe是一个环形的,为了说明方便,我们假设将一个COSS文件的stripe编号为1,2,3…..N。COSS文件新建起来时,Squid会记录当前使用的Stripe号为1。同时,在系统维护一个stripe大小的内存块stripe->membuf(默认是1M)。当有Object新建时,Squid将该Object的文件写到stripe->membuf,当stripe->membuf写满或不能容下新来的Object时,Squid会将该stripe交换(Swapout)到Disk上对应的stripe上。同时,将当前stripe指向2号stripe,并把新文件加到2号stripe->membuf。同理,当2号stripe->membuf满时,再swapout,并使用3号,依次类推。当整个COSS的Disk stripe写满,则循环使用1号(这就是所谓的成环)。当前游标所到之处的stripe,则会被重写(覆盖)。
       从这么看,似乎COSS与生俱来就有老化功能,为什么还要费力开发Relocation呢?我的理解是,当COSS文件的Object被删除时,如果不使用relocation就会引起COSS内部碎片严重,影响服务效果。
  
       Relocaton是如何工作的?
       当Squid访问Object时,首先会依据用户的配置(overwrite-percent),判断该Object是否需要relocation。如果需要,则将该Object读出来之后,放到当前stripe->membuf,待membuf写满后swapout到当前disk stripe。从而该Object就可以在最长的时间内保存在COSS文件中了(只到游标绕COSS一个圈,再次到达时,才会覆盖),从而实现了LRU类似的作用。
       可以看到,由于Relocation的原因,本身只有Read操作的IO却增加了write操作,这是COSS的一个缺点。但COSS毕竟利用大文件来存储小文件,从而避免了AUFS频繁的Open、Close系统调用操作。但可以看到,使用COSS会增加io操作的次数,从而占用过多IOPS(read/write)。
  
2. COSS实现分析
2.1. Squid FileSystem架构分析

      <插图>

2.2. COSS所使用的核心数据结构
 2.2.1. SwapDir
  /*
   *  对应cache_dir的一行配置
   */
  struct _SwapDir {
   const char *type;
   int cur_size; //本目录所有Object的大小的总和,以k为单位
   int low_size; //本目录由max_size及lowWaterMark算出来的low water字节数,kB
   int max_size; //本目录支持的最大使用字节数, kB
   char *path;  //本目录的路径
   int index;   /* This entry’s index into the swapDirs array */
   squid_off_t min_objsize; //本目录支持的最小Object
   squid_off_t max_objsize; //本目录支持的最大Object
   RemovalPolicy *repl;  //本目录的老化策略handler
   int removals;    //FIXME:本参数没有使用
   int scanned;    //FIXME:本参数没有使用
   struct {
    //当前Object选择存放到本目录时,设置为1,仅用于cachemgr
    unsigned int selected:1; 
    //本目录在cache_dir配置中设置为read only
    unsigned int read_only:1;
   } flags;
  
   /* 以下为该FS对应的各操作函数指针 */
   STINIT *init;  /* Initialise the fs */
   STCHECKCONFIG *checkconfig; /* Verify configuration */
   STNEWFS *newfs;  /* Create a new fs */
   STDUMP *dump;  /* Dump fs config snippet */
   STFREE *freefs;  /* Free the fs data */
   STDBLCHECK *dblcheck; /* Double check the obj integrity */
   STSTATFS *statfs;  /* Dump fs statistics */
   STMAINTAINFS *maintainfs; /* Replacement maintainence */
   STCHECKOBJ *checkobj; /* Check if the fs will store an object */
   STCHECKLOADAV *checkload; /* Check if the fs is getting overloaded .. */
   /* These two are notifications */
   STREFOBJ *refobj;  /* Reference this object */
   STUNREFOBJ *unrefobj; /* Unreference this object */
   STCALLBACK *callback; /* Handle pending callbacks */
   STSYNC *sync;  /* Sync the directory */
  
   /* 以上为对本类FS的Object的操作函数 */
   struct {
    STOBJCREATE *create;
    STOBJOPEN *open;
    STOBJCLOSE *close;
    STOBJREAD *read;
    STOBJWRITE *write;
    STOBJUNLINK *unlink;
    STOBJRECYCLE *recycle;
   } obj;
  
   /* 日志操作函数指针 */
   struct {
    STLOGOPEN *open;
    STLOGCLOSE *close;
    STLOGWRITE *write;
    struct {
     STLOGCLEANSTART *start;
     STLOGCLEANNEXTENTRY *nextentry;
     STLOGCLEANWRITE *write;
     STLOGCLEANDONE *done;
     void *state;
    } clean;
    int writes_since_clean;
   } log;
  
   struct {
    int blksize; //本文件系统的块大小
   } fs;
  
   void *fsdata;
  };

       这是Squid FileSystem的一个抽象,对于每一个具体的实现,如COSS,则会利用利用自己的open, close, create等函数注册到这些API中。这种实现与Linux内核的Filesystem的实现方式一致。
       某种意义上讲,我们可以基于这个抽象层自己开发适合自己业务的文件系统层。这就叫抽象层,叫接口层。是OS实现中重要的思想与技术。做过Linux内核开发的人应该很好理解。

 2.2.2. struct _cossinfo
          仅列出我们关心数据成员。

  struct _cossinfo {
   dlink_list membufs; //用link快速指向memory stripe
   
   //一个快的指针,总是指向正在使用的Disk Stripe的membuf
   struct _cossmembuf *current_membuf;
   
   //指向整个COSS的当前offset,可能大于maxoffset
   off_t current_offset;   /* in bytes */
   
       float minumum_overwrite_pct;    //overwrite-percent的配置值
   int minimum_stripe_distance; //由overwrite-percent计算的当前游标与Object原址所在施标大于distance时,就进行Object的搬迁,唯一用途在storeCossRelocateRequired的判断
   
   //以下是Disk Stripes信息
       int numstripes;     //按COSS文件大小计算的,可以存的numstripes数
       struct _cossstripe *stripes; //总大小是COSS文件支持的最大Disk stripe数,是一个以numstripes为下标的数组
   int curstripe;  //当前正在使用的stripe的号
   int max_disk_nf;    //等于coss文件的最大Block数
   
   //以下是Memory Stripes信息
   off_t current_memonly_offset;
   struct _cossmembuf *current_memonly_membuf;
   int nummemstripes;              //默认是10个,内存stripe的大小
   
   //指向内存stripe,是一个指针数组,大小是nummemstripes
   struct _cossstripe *memstripes; //仅在storeCossMaybeFreeBuf时清除,是在writeMemBufDone时调用
   int curmemstripe;       //并不是内存stripe占用的数目,而是当前空闲使用的stripe
   …………
  }

       Cossinfo是每一个COSS文件对应一个,总体上记录COSS的各Stripe分配与映射。
       特别注意成员cossinfo->stripes,对于Disk Stripe,在程序初始化时,就将cossinfo->stripes分配成一个numstripes大小(最大disk stripe数目)的数组。Cossinfo->stripes[n]就分别对应这N个disk stripe。里面有足够的信息记录每一个disk stripe的使用情况。
       另一个重要的成员是cossinfo-> memstripes。与Disk Stripe的实现与使用形式基本一致。

       Squid就是利用这这个数据结构来管理整个COSS的,我们下面通过流程分析来理解。

 2.2.3. cossstripe
  struct _cossstripe {
      int id;
      int numdiskobjs; //本stripe的object数目
      int pending_relocs;
      struct _cossmembuf *membuf; //正在写的object{s!} mem_buf,写满后同步到disk?
  dlink_list objlist;     //本stripe中支持的objectslist,类型是StoreEntry。
  };
 
 2.3. 关键流程分析
  2.3.1. rebuild
        当rebuild时,Squid会依次打开每一个COSS文件,每读到一个stripe,不将该stripe的相关信息加入到cossinfo->stripes[n]中,n是coss文件中逻辑的stripe块号。将该stripe的object信息读出后,放到cossinfo->stripe[n]下,某个object信息则放到cossinfo->stripe[n]-> objlist中。由于类型是StoreEntry,其中的其中的storeentry->swap_filen与storeentry->swap_dirn通过COSS一定的映射关系就可以算了来,在COSS文件的Offset,利用fseek就可以读取了。
        简单的说,rebuild过程通过依次分析每一个stripe,将其中存在object信息还原到storeEntry的hash,以及cossinfo->stripes[n]中,就完成了整个rebuild.
  
  2.3.2. Cache HIT时访问Object:storeCossOpen
   CossOpen的伪代码表示如下:
   storeCossOpen()
   {
    //在CossInfo的Mem Stripe找,看要访问的Object是否在Memory Stripe中
    storeCossMemPointerFromDiskOffset
    
    if ( Mem stripe HIT) {
     //将该mem stripe锁定,不允许被swapout到Disk
     //即使在mem stripe都被占用的情况下
     storeCossMemBufLock
    } else {
     If (storeCossRelocateRequired) {
      //当满足relocation的要求时,object很久没有被访问过了
      storeCossAllocate
     } else {
      //object刚被访问过,就存在后面不远的stripe处,不必马上relocation
      storeCossMemOnlyAllocate
      //这个函数内部,当mem stripe占用满了时,就会提醒
      // storeCossCreateMemOnlyBuf: no free membufs. 
      //You may need to increase the value of membufs
    
      If (mem stripe占满了) {
       //内部会将已经写满的stripe写到Disk上,同relocation的情况
      storeCossAllocate
      ………………
      }
     }
     ………………..
    }
   }

3. 案例分析
3.1. 案例1
 案例描述:
         对Squid服务器做了加压的尝试,使用COSS,但log里面出现了
         2009/02/22 10:26:27| storeCossCreateMemOnlyBuf: no free membufs.  You may need to increase the value of membufs on the /cache/coss13 cache_dir
          然后导致cache hit service time达到了秒级的响应时间,正常的情况下一般在6ms左右

 技术分析
         从上面的分析可以看到,当提醒“storeCossCreateMemOnlyBuf: no free membufs.  You may need to increase the value of membufs”时,是由于mem stripe被占满时才提醒的。正常情况下,当mem stripe的M个stripe都占满时,squid会将部分mem stripe swapout到COSS文件上。但当storeCossMemBufLock锁定了某个mem stripe的话,则不会执行swapout。而当某个mem stripe中的object正在被访问(Object Cache HIT)时,则mem stripe被Lock,服务完成后,即会Unlock。
         这个信息是在storeCossOpen(Cache HIT)的内部执行过程中被输出的,因此分析这个函数是关键。
         因此,本例的结论应该是:
         提示信息是由于正在被访问的object在不久前被访问过(这里的不久是指,当overwrite-percent缺省为50%时,是指在整个COSS文件遍历一次的50%的时间内。如果不理解的话,看一下代码,minimum_stripe_distance的计算方法),因此COSS的relocation机制storeCossRelocateRequired认为该Object不应relocation,所以希望用mem stripe来存放。但找不到空闲的mem stripe来存放这个object,所以只能relocation(后果是relocation使得这个被访问的object应当前游标下的stripe,下次再访问时这个object时,这个stripe又足够新,以使得又不满足relocation条件,从而又希望用mem stripe来存放——形成恶性循环)。
          之所以找不到空闲的mem stripe,极有可能是由于Squid负载过重,导致每一个Object服务时间长(Mem Stripe中的object的Lock周期也长),从而由于并发Lock的数目也增大,直接导致mem stripe被占光。
          从之前没有出现这种现象来推测,应该通过降低响应时间来解决这个问题。当然,从之前的技术分析可以看到,修改overwrite-percent,加大membufs数目都可以解决这个问题。但根本的原因仍然是Lock与Unlock的周期过程,即热门的Object服务时间过长。

4. 关于使用COSS的建议
         从我们对COSS的技术分析可以看到:
               .COSS使用stripe与block来管理文件,不能充分利用硬盘空间
               .COSS由于使用relocation,导致增加写操作
               .COSS的rebuild过程需要分析整个COSS文件,因此费的时间非常长,而且在rebuild过程中不能服务
               .由于fileno只有24位,因此,支持的COSS文件大小有上限
               .当COSS文件有文件删除操作(Cache Purge)时,导致COSS内部大量空洞,每个stripe的object数目变少,读写效率下降
                .COSS无法有效支持基于目录的刷新扩展,以及更深层的内容管理
                .COSS支持的Object大小有一个上限值

             COSS的优势:
                  .较AUFS、UFS来说,避免了大量(每个Object访问一次)open/close系统调用
                  .更加可能使用相对连续的空间来存放文件(操作系统优先使用连接空间的分配,在COSS创建时),可能能有效利用了OS的ReadAhead预读作用(预读的stripe中,可能包括后面将要访问的object)

           上面的分析可能不够全面,但我们仍可以看到,对于普通硬盘来说,使用COSS可能会对小文件的服务性能有帮助(主要是通过减少open/close,代替的是使用大量的lseek),但当有以下情况下,COSS可能不是最佳选择:
             .使用SSD硬盘的设备。SSD读能力非常强,但写能力较差,COSS会增加写操作,反而较AUFS差
            .有频繁的文件更新或删除(Purge)操作
            .当访问的热点文件比较集中,但大于mem stripe可以存放的大小时。可能引起mem stripes满后,频繁的relocation,而从陷入案例一类似的恶性循环。
            .对于Squid启动速度有较高要求的

         最后,是否使用多Squid架构,以及使用什么样的Filesystem,本质上,要依据业务来定。从计算机体系架构上来看,整个系统简单的看,主要由四个资源组成:计算资源CPU,存储资源(内存与外存储),IO(这里特指网卡,因为外存也是通过IO),以及连接他们的总线。
         要对Squid做优化,首先要看看对于特点的业务来说,这四个资源什么是瓶颈,是CPU还是IO,充分利用多CPU可以使Squid充分利用多CPU的计算资源,减少“串行”操作的等待时间。但是,当多个Squid使用多个coss文件时,本身也会增加一些开销,其中一项就是增加IO的竞争开销。如果参数设置不合理,IO竞争的开销会使IO的等待时间更多(使用iostat –x的await、avgqu-sz可以分析)


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Squid是一种高性能的代理服务器,可以用于缓存Web页面,提供访问控制,以及其他一些网络服务。以下是Squid的配置文件详解: 1. 基础配置 Squid配置文件的默认位置是/etc/squid/squid.conf,可以通过编辑此文件来实现基本配置。以下是一些基本配置: ``` http_port 3128 cache_mem 100 MB maximum_object_size 4096 KB ``` - http_port:指定Squid代理服务器监听的端口号,默认为3128。 - cache_mem:指定Squid使用的缓存大小,默认为32 MB。 - maximum_object_size:指定Squid可以缓存的最大对象大小,默认为4 MB。 2. 访问控制 Squid可以通过访问控制列表(ACL)来限制用户的访问。以下是一些示例配置: ``` acl localnet src 192.168.0.0/16 http_access allow localnet http_access deny all ``` - acl:定义一个ACL,指定IP地址范围或其他限制条件。 - http_access:指定允许或拒绝访问的ACL。 - allow:允许指定的ACL访问代理服务器。 - deny:拒绝指定的ACL访问代理服务器。 - all:表示所有请求都匹配该规则。 3. 缓存控制 Squid可以缓存Web页面,以便更快地访问。以下是一些示例配置: ``` cache_dir ufs /var/spool/squid 100 16 256 refresh_pattern ^ftp: 1440 20% 10080 refresh_pattern ^gopher: 1440 0% 1440 refresh_pattern -i (/cgi-bin/|\?) 0 0% 0 ``` - cache_dir:指定Squid使用的缓存目录。 - ufs:指定使用ufs文件系统。 - /var/spool/squid:缓存目录的位置。 - 100:指定缓存目录的大小(单位:MB)。 - 16:指定缓存目录中的目录数量。 - 256:指定缓存目录中的文件数量。 - refresh_pattern:指定Squid对缓存页面的刷新策略。 - ^ftp::对FTP页面进行缓存。 - ^gopher::对Gopher页面进行缓存。 - (/cgi-bin/|\?):对CGI脚本和动态页面不进行缓存。 4. 日志记录 Squid可以记录访问日志和错误日志。以下是一些示例配置: ``` access_log /var/log/squid/access.log squid cache_log /var/log/squid/cache.log ``` - access_log:指定Squid记录访问日志的位置。 - /var/log/squid/access.log:访问日志文件的位置。 - squid:指定访问日志的格式。 - cache_log:指定Squid记录错误日志的位置。 - /var/log/squid/cache.log:错误日志文件的位置。 这些是Squid配置文件中的一些基本配置项。通过编辑这些配置项,可以实现更高效、更安全的代理服务器。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值