View on GitHub

Wills' blog

  • home | github | resume |
  • 【译】memcached介绍(3)

    04 Mar 2014

    翻译来自日本某技术网站的入门级文章。链接

    译者水平有限翻译如有误请指出。

    因为memcached是缓存的原因,以指定的数据不会在服务器常驻作为而前提导入的机制。本次讲memcached的清除机制,然后讲memcached的最新动态:二进制协议和外部引擎支持。

    memcached在数据清除方面也使得资源得到有效的利用

    memcached不能将实际的数据删除

    前面介绍过,memcached不释放分配到的内存。记录在超市之后,客户端仅仅是看不到(变的透明),这个领域将被再利用。

    lazy Expiration

    memcached不监视记录是否超市,而是在get操作时检查timestamp来判断是否超时。这个技术被叫做Lazy expiration。所以不会因为memcached的监视而消耗CPU的资源。

    LRU: 有效的从缓存清除的数据的机制

    memcached在优先再利用过期的数据,在没有空间添加新的数据的时候使用Least Recently Used(LRU)的策略来获得存储空间。就像名字里面的所说的,最近最少使用的记录将作为删除对象。所以在memcached的内存不足的时候(不能从slab里面取得内存的时候),最近没有被引用到的纪录被找出来,这格记录的内存空间就会被新的记录使用。从缓存的实用性来看这个策略是一个理想的策略。

    从usecase来看,LRU的策略也有变得碍手碍脚的可能。当存在这种情况的时候,在memcached启动的时候使用-M参数将LRU无效化。

    $ memcached -M -m 1024
    

    启动时不得不注意的一点是用-m选项指定最大的内存空间。如果没有指定的话默认将以64MB的空间启动。

    -M选项启动之后,当内存空间不足是,memcached会返回error。因为memcached不是存储而是缓存,所以使用LRU启动是推荐的选择。

    memcached的最新动向

    现在memcached的路线图有两大目标。一个是二进制协议的策划和实现,另一个是能装载外部的引擎。

    二进制协议有关内容

    采用二进制协议的理由是省去文本协议的解析处理,将已经很高速的memcached性能更上一层。另外还为了减小采用文本协议带来的脆弱性。实现实际上已经做了非常多,开发的repo已经在web公开。链接

    二进制协议的形式

    协议的包是固定为24字节长的帧,之后接key-value和无结构数据。实际的形式如下(从设计书中摘取)

    Byte/     0       |       1       |       2       |       3       |   
        /              |               |               |               |   
       |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
       +---------------+---------------+---------------+---------------+
      0/ HEADER                                                        /   
       /                                                               /   
       /                                                               /   
       /                                                               /   
       +---------------+---------------+---------------+---------------+
     24/ COMMAND-SPECIFIC EXTRAS (as needed)                           /   
      +/  (note length in th extras length header field)               /   
       +---------------+---------------+---------------+---------------+
      m/ Key (as needed)                                               /   
      +/  (note length in key length header field)                     /   
       +---------------+---------------+---------------+---------------+
      n/ Value (as needed)                                             /   
      +/  (note length is total body length header field, minus        /   
      +/   sum of the extras and key length body fields)               /   
       +---------------+---------------+---------------+---------------+
      Total 24 bytes
    

    正如上面看到的,包的形式变的非常的简单。在这个形式当中,值得留意的是占有26个字节的HEADER空间。HEAD有Request和response两种。HEADER里卖弄有表示包有效性的Magic字节,命令的种类,key的长度,value的长度等等信息。形式如下:

    request

    Byte/     0       |       1       |       2       |       3       |
        /              |               |               |               |
       |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
       +---------------+---------------+---------------+---------------+
      0| Magic         | Opcode        | Key length                    |
       +---------------+---------------+---------------+---------------+
      4| Extras length | Data type     | Reserved                      |
       +---------------+---------------+---------------+---------------+
      8| Total body length                                             |
       +---------------+---------------+---------------+---------------+
     12| Opaque                                                        |
       +---------------+---------------+---------------+---------------+
     16| CAS                                                           |
       |                                                               |
       +---------------+---------------+---------------+---------------+
    

    response

    Byte/     0       |       1       |       2       |       3       |
        /              |               |               |               |
       |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
       +---------------+---------------+---------------+---------------+
      0| Magic         | Opcode        | Key length                    |
       +---------------+---------------+---------------+---------------+
      4| Extras length | Data type     | Reserved                      |
       +---------------+---------------+---------------+---------------+
      8| Total body length                                             |
       +---------------+---------------+---------------+---------------+
     12| Opaque                                                        |
       +---------------+---------------+---------------+---------------+
     16| CAS                                                           |
       |                                                               |
       +---------------+---------------+---------------+---------------+
    

    如果想要知道具体每个域是什么意思,可以看memcached的开发包docs文件夹下的protocol_binary.txt文件。

    看了HEADER在意的地方

    看了HEADER之后我想到的是key的临界值巨大。现在的memcached的协议里面有key的长度最长250个字节的限制。二级制协议当中key长度用两个字节表示,也就是可以处理长度为65535的key。虽然key长度250在实际的usecase已经很少见,但是二进制协议一旦发布将能处理巨大长度的key。二进制协议将会在1.3版本中得到支持。

    外部引擎的对应

    去年实验性的对memcached的线程层面进行了能够加插件的改造。链接

    这个改造给了Mysql的Brian Aker看了之后代码被发给了memcached的邮件列表中的人,然后他们将这个记在了路线图中。现在与memcached的开发者之一的TrndNorbye一起开发。与海外的共同开发的时候虽然时差是个难题,但是仍然国内公开了插件形式的模型。可以从官网下载。

    对应外部引擎的重要性

    时尚存在很多memcached的派生版本的理由是希望多少牺牲一些性能来达到数据的持久化和实现冗长性。与现在的开发无关,以前在mixi的时候就有过重新开发memcached的时候。

    外部的引擎的架构里,memcached能够处理网络和事件等复杂的处理。所以,现在被memcached烦恼的与存储引擎相关的事情,今后就可以通过各种各样的引擎插件来完成。

    简介的API成功设计的关键

    在这个项目当中我们非常重视的是API的设计。action的数量过多的话会使引擎开发人员觉得很麻烦,太过复杂会使得实现的门槛变得很高。因为这样第一版本里面只留下了13个API接口。详细的内容因为太长这里省略,下面这些是引擎须要的操作。

    想详细知道具体细节的话请查看开发包的engine.h头文件。

    现行架构的修改

    memcached对应外部的存储引擎的难点在于通过web和时间机制处理的记录,以及与内存存储结合紧密的处理。这个现象也被叫做tightly coupled。如果不把现行的内存存世的记录从还行服务器独立出来的话,外部引擎就不能有效的对应。所以,基于我们设计的API的memcached被重构成一下(图中日文我就不翻译了):

    1

    重构后对1.2.5版本以及采用了二进制协议的版本做了评测,确认了对性能没有影响。


    [click to comment]