redis与memcached的底层数据结构与存取算法

redis比memcatched更快的原因
Redis支持哪几种数据类型?每种数据类型的底层结构?

5中数据类型:String、List、Set、Sorted Set、hash;8种底层数据结构。

redis底层数据结构

Redis中的一个对象的结构体表示如下:
/*
 * Redis 对象
 */
typedef struct redisObject {
    // 类型
    unsigned type:4;        
    // 不使用(对齐位)
    unsigned notused:2;
    // 编码方式
    unsigned encoding:4;
    // LRU 时间(相对于 server.lruclock)
    unsigned lru:22;
    // 引用计数
    int refcount;
    // 指向对象的值
    void *ptr;
} robj;
一共8种数据结构:int,empstr,raw,ziplist,linkedlist,intset,dict,skip
empstr:embstr编码的简单动态字符串,对应于redis的string类型
raw:简单动态字符串,对应于redis的string类型
ziplist:是一种压缩链表,它的好处是更能节省内存空间,因为它所存储的内容都是在连续的内存区域当中的。当列表对象元素不大,每个元素也不大的时候,就采用ziplist存储。

如linkedlist编码的numbers的列表对象如下图:


skip:跳表,下面给出skip的结构图

String:int,empstr,raw

如果一个字符串对象的内容可以转换为long。那么该字符串就会被转换成long类型,对象的ptr就会指向该long,并且对象的类型也用int表示。字符串的长度小于39字节(3.2之后改成了44),就用embstr。否则就使用传统的raw对象。
list:linkedlist,ziplist
hash:ziplist,dict
set:intset,dict
sortset:ziplist skip+dict

memcache的底层数据结构

MemCache最重要的莫不是内存分配的内容了,MemCache采用的内存分配方式是固定空间分配,还是自己画一张图说明:

这张图片里面涉及了slab_class、slab、page、chunk四个概念,它们之间的关系是:
1、MemCache将内存空间分为一组slab
2、每个slab下又有若干个page,每个page默认是1M,如果一个slab占用100M内存的话,那么这个slab下应该有100个page
3、每个page里面包含一组chunk,chunk是真正存放数据的地方,同一个slab里面的chunk的大小是固定的
4、有相同大小chunk的slab被组织在一起,称为slab_class
MemCache内存分配的方式称为allocator,slab的数量是有限的,几个、十几个或者几十个,这个和启动参数的配置相关。
MemCache中的value过来存放的地方是由value的大小决定的,value总是会被存放到与chunk大小最接近的一个slab中,比如slab[1]的chunk大小为80字节、slab[2]的chunk大小为100字节、slab[3]的chunk大小为128字节(相邻slab内的chunk基本以1.25为比例进行增长,MemCache启动时可以用-f指定这个比例),那么过来一个88字节的value,这个value将被放到2号slab中。

redis和memcatched是怎么根据key来存储和获取value的?

Redis集群写入/查询数据原理(理论)

redis集群数据存储原理:
    在redis cluster中,如果想要存入一个key-value,
    这个key首先会通过CRC16算法取余(和16384取余),
    结果会对应上0-16383之间的哈希槽(hash slot)
    最后,redis cluster会将key-value放置在对应的哈希槽中。

redis集群数据获取原理:
    当client向redis cluster中的任意一个节点发送与数据库key有关的命令时,
    接收命令的节点会计算出要处理的key属于哪个哈希槽(hash slot),
    并且先检查这个hash slot是否属于自己(管辖):
        如果key所在的槽正好属于自己(管辖),节点会直接执行这个key相关命令。
        如果key所在的槽不属于自己(管辖),那么节点会给client返回一个MOVED错误,
        指引client转向负责对应槽的节点,并客户端需要再次发送想要执行的和key相关的命令。

Memcached写入和查询数据的原理

MemCache访问模型图:


特别澄清一个问题,MemCache虽然被称为"分布式缓存",但是MemCache本身完全不具备分布式的功能,MemCache集群之间不会相互通信(与之形成对比的,比如JBoss Cache,某台服务器有缓存数据更新时,会通知集群中其他机器更新缓存或清除缓存数据),所谓的"分布式",完全依赖于客户端程序的实现,就像上面这张图的流程一样。
同时基于这张图,理一下MemCache一次写缓存的流程:
1、应用程序输入需要写缓存的数据
2、API将Key输入路由算法模块,路由算法根据Key和MemCache集群服务器列表得到一台服务器编号
3、由服务器编号得到MemCache及其的ip地址和端口号
4、API调用通信模块和指定编号的服务器通信,将数据写入该服务器,完成一次分布式缓存的写操作
读缓存和写缓存一样,只要使用相同的路由算法和服务器列表,只要应用程序查询的是相同的Key,MemCache客户端总是访问相同的客户端去读取数据,只要服务器中还缓存着该数据,就能保证缓存命中。

这种MemCache集群的方式也是从分区容错性的方面考虑的,假如Node2宕机了,那么Node2上面存储的数据都不可用了,此时由于集群中Node0和Node1还存在,下一次请求Node2中存储的Key值的时候,肯定是没有命中的,这时先从数据库中拿到要缓存的数据,然后路由算法模块根据Key值在Node0和Node1中选取一个节点,把对应的数据放进去,这样下一次就又可以走缓存了,这种集群的做法很好,但是缺点是成本比较大。

memcached根据key路由到合适的服务器有两种算法:

1、余数Hash--不好
比方说,字符串str对应的HashCode是50、服务器的数目是3,取余数得到2,str对应节点Node2,所以路由算法把str路由到Node2服务器上。由于HashCode随机性比较强,所以使用余数Hash路由算法就可以保证缓存数据在整个MemCache服务器集群中有比较均衡的分布。
如果不考虑服务器集群的伸缩性,那么余数Hash算法几乎可以满足绝大多数的缓存路由需求,但是当分布式缓存集群需要扩容的时候,就难办了。如上面hashCode为50的时候,服务器数为3时,对应节点为node2;增加了4台机器,此时在用hashCode为50来对7取余,定位到了node1,类似的就会存在好多缓存的数据失效。
这个问题有解决方案,解决步骤为:
(1)在网站访问量低谷,通常是深夜,技术团队加班,扩容、重启服务器
(2)通过模拟请求的方式逐渐预热缓存,使缓存服务器中的数据重新分布
2一致性hash算法--更优
首先请考虑一个圆,在该圆上分布了多个点,以表示整数0到1023。这些整数平均分布在整个圆上:

 

而在上图中,我们则突出地显示了6个蓝点。这六个蓝点基本上将该圆进行了六等分。而它们所对应的就是在当前Memcached缓存系统中所包含的三个 Memcached实例m1,m2以及m3。好,接下来我们则对当前需要存储的数据执行哈希计算,并找到该哈希结果900在该圆上所对应的点:

 可以看到,该点在顺时针距离上离表示0的那个蓝点最近,因此这个具有哈希值900的数据将记录在Memcached实例m1中。
 如果其中的一个Memcached实例失效了,那么需要由该实例所记录的数据将暂时失效,而其它实例所记录的数据仍然还在:


从上图中可以看到,在Memcached实例m1失效的情况下,值为900的数据将失效,而其它的值为112和750的数据将仍然记录在 Memcached实例m2及m3上。也就是说,一个节点的失效现在将只会导致一部分数据不再在缓存系统中存在,而并没有导致其它实例上所记录的数据的目标实例发生变化。

但是我们还不得不考虑另一个问题,那就是在一个服务的服务端缓存仅仅由一个或几个Memcached实例组成的情况。在这种情况下,其中一个 Memcached实例失效是较为致命的,因为数据库以及服务器实例将接收到大量的需要进行复杂计算的请求,并将最终导致服务器实例和数据库过载。因此在 设计服务端缓存时,我们常常采取超出需求容量的方法来定义这些缓存。例如在服务实际需要5个Memcached结点时我们设计一个包含6个节点的服务端缓 存系统,以增加整个系统的容错能力。

memcached一致性算法更优的原因

余数hash,三台机器原来有HashCode为0~19的20个数据,那么:

现在我扩容到4台,加粗标红的表示命中,命中率只有30%,而且大量的无法命中的数据还在原缓存中在被移除前占据着内存。

如果是一致性hash,如下图

 

m2的hash范围:0-170,512-682
m3的hash范围:171-340,682-853
m1的hash范围:341-512,853-1024

现在增加机器m4,必须说明上图中m4增加的点是85和597,所以受影响的数据范围仅有m2的0-85和512-595,那么受影响的范围只有17个百分点。这是完全可以接受的

借鉴;https://blog.csdn.net/qq794096244/article/details/79557360

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值