一、 Memcache与Redis的区别
1)、存储方式
Memecache把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。
Redis有部份存在硬盘上,这样能保证数据的持久性。
2)、数据支持类型
Memcache对数据类型支持相对简单。
Redis有复杂的数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)
3)、使用底层模型不同
它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。
Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。
4)、value大小
Redis: 一个key或是value大小最大是512M;
memcached的简单限制就是键(key)和item的限制。最大键长为250个字符。可以接受的储存数据不能超过1MB,因为这是典型slab 的最大值。
二、 数据类型
String:缓存、限流、计数器、分布式锁、分布式Session
Hash:存储用户信息、用户主页访问量、组合查询
List:微博关注人时间轴列表、简单队列
Set:赞、踩、标签、好友关系
Zset:排行榜
1. String数据
常用命令:set/get/decr/incr/mget 等;
应用场景:String 是最常用的一种数据类型,普通的 key/value 存储都可以归为此类;
实现方式:String 在 redis 内部存储默认就是一个字符串,被 redisObject 所引用,当遇到 incr、decr 等操作时会转成数值型进行计算,此时 redisObject 的 encoding 字段为 int。
2. Hash数据
常用命令:hget/hset/hgetall 等
应用场景:我们要存储一个用户信息对象数据,其中包括用户 ID、用户姓名、年龄和生日,通过用户 ID 我们希望获取该用户的姓名或者年龄或者生日;
实现方式:Redis Hash 对应 Value 内部实际就是一个 HashMap,实际这里会有 2 种不同实现,这个 Hash 的成员比较少时 Redis 为了节省内存会采用类似
一维数组的方式来紧凑存储,而不会采用真正的 HashMap 结构,对应的 value redisObject 的 encoding 为 zipmap, 当成员数量增大时会自动转成真正的 HashMap,
此时 encoding 为 ht
3. List
常用命令:lpush/rpush/lpop/rpop/lrange 等;
应用场景:Redis list 的应用场景非常多,也是 Redis 最重要的数据结构之一,比如 twitter 的关注列表,粉丝列表等都可以用 Redis 的 list 结构来实现;消息队列;
实现方式:Redis list 的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,Redis 内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。
4. Set数据
常用命令:sadd/spop/smembers/sunion 等;
应用场景:Redis set 对外提供的功能与 list 类似是一个列表的功能,特殊之处在于 set 是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,
set 是一个很好的选择,并且 set 提供了判断某个成员是否在一个 set 集合内的重要接口,这个也是 list 所不能提供的;
实现方式:set 的内部实现是一个 value 永远为 null 的 HashMap,实际就是通过计算 hash 的方式来快速排重的,这也是 set 能提供判断一个成员是否在集合内的原因
5. Sorted Set数据
常用命令:zadd/zrange/zrem/zcard 等;
应用场景:Redis sorted set 的使用场景与 set 类似,区别是 set 不是自动有序的,而 sorted set 可以通过用户额外提供一个优先级 (score) 的参数来为成员排序,
并且是插入有序的,即自动排序。当你需要一个有序的并且不重复的集合列表,那么可以选择 sorted set 数据结构,比如 twitter 的 public timeline 可以以发表时间作为 score 来存储,这样获取时就是自动按时间排好序的。
实现方式:Redis sorted set 的内部使用 HashMap 和跳跃表 (SkipList) 来保证数据的存储和有序,HashMap 里放的是成员到 score 的映射,而跳跃表里存放的
是所有的成员,排序依据是 HashMap 里存的 score, 使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。
三、 Redis 持久化
Redis 可以以 master-slave 的方式配置服务器,Slave 节点对数据进行 replica 备份,Slave 节点也可以充当 Read only 的节点分担数据读取的工作。
Redis 虽然是基于内存的存储系统,但是它本身是支持内存数据的持久化的,而且提供两种主要的持久化策略:RDB 快照和 AOF 日志
Redis 内建支持两种持久化方案,snapshot 快照和 AOF 增量 Log 方式。快照顾名思义就是隔一段时间将完整的数据 Dump 下来存储在文件中。A
OF 增量 Log 则是记录对数据的修改操作(实际上记录的就是每个对数据产生修改的命令本身),两种方案可以并存,也各有优缺点
四、 Redis 的 7 个应用场景
1. 缓存 —— 热数据:
热点数据(经常会被查询,但是不经常被修改或者删除的数据)
2. 计数器: 统计点击数等应用
3. 队列: 相当于消息系统; 队列不仅可以把并发请求变成串行,并且还可以做队列或者栈使用
4. 位操作(大数据处理):
用于数据量上亿的场景下,例如几亿用户系统的签到,去重登录次数统计,某用户是否在线状态等等。
想想一下腾讯 10 亿用户,要几个毫秒内查询到某个用户是否在线,你能怎么做?千万别说给每个用户建立一个 key,然后挨个记(你可以算一下需要的内存会很恐怖,而且这种类似的需求很多,腾讯光这个得多花多少钱。。)好吧。这里要用到位操作 —— 使用 setbit、getbit、bitcount 命令。
原理是:redis 内构建一个足够长的数组,每个数组元素只能是 0 和 1 两个值,然后这个数组的下标 index 用来表示我们上面例子里面的用户 id(必须是数字哈),那么很显然,这个几亿长的大数组就能通过下标和元素值(0 和 1)来构建一个记忆系统,上面我说的几个场景也就能够实现。用到的命令是:setbit、getbit、bitcount
5. 分布式锁与单线程机制:
验证前端的重复请求(可以自由扩展类似情况),可以通过 redis 进行过滤:每次请求将 request Ip、参数、接口等 hash 作为 key 存储 redis(幂等性请求),设置多长时间有效期,然后下次请求过来的时候先在 redis 中检索有没有这个 key,进而验证是不是一定时间内过来的重复提交
秒杀系统,基于 redis 是单线程特征,防止出现数据库 “爆破”
全局增量 ID 生成,类似 “秒杀”
6. 最新列表:
例如新闻列表页面最新的新闻列表,如果总数量很大的情况下,尽量不要使用 select a from A limit 10 这种 low 货,尝试 redis 的 LPUSH 命令构建 List,
一个个顺序都塞进去就可以啦。不过万一内存清掉了咋办?也简单,查询不到存储 key 的话,用 mysql 查询并且初始化一个 List 到 redis 中就好了。
7. 排行榜
谁得分高谁排名往上。命令:ZADD(有续集,sorted set)
五、 Redis集群的数据一致性(redis分布式)
Redis 集群没有使用一致性hash, 而是引入了哈希槽的概念。
Reds 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽。
这种结构很容易添加或者删除节点,并且无论是添加删除或者修改某一个节点,都不会造成集群不可用的状态。
使用哈希槽的好处就在于可以方便的添加或移除节点。
当需要增加节点时,只需要把其他节点的某些哈希槽挪到新节点就可以了;
当需要移除节点时,只需要把移除节点上的哈希槽挪到其他节点就行了;
在这一点上,我们以后新增或移除节点的时候不用先停掉所有的 redis 服务
通过key做一致性哈希,实现key对应redis结点的分布。
一致性哈希的实现:
l hash值计算:通过支持MD5与MurmurHash两种计算方式,默认是采用MurmurHash,高效的hash计算。
l 一致性的实现:通过java的TreeMap来模拟环状结构,实现均匀分布
六、 MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据
相关知识:redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。
redis 提供 6种数据淘汰策略:
voltile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
no-enviction(驱逐):禁止驱逐数据
七、 Redis哨兵机制(Sentinel)
Redis的哨兵(sentinel) 系统用于管理多个 Redis 服务器:
监控(Monitoring): 哨兵(sentinel) 会不断地检查你的Master和Slave是否运作正常。
提醒(Notification):当被监控的某个 Redis出现问题时, 哨兵(sentinel) 可以通过 API 向管理员或者其他应用程序发送通知。
自动故障迁移(Automatic failover):当一个Master不能正常工作时,哨兵(sentinel) 会开始一次自动故障迁移操作,它会将失效Master的其中一个Slave升级为新的Master,
并让失效Master的其他Slave改为复制新的Master; 当客户端试图连接失效的Master时,集群也会向客户端返回新Master的地址,使得集群可以使用Master代替失效Master。
哨兵(sentinel) 是一个分布式系统,你可以在一个架构中运行多个哨兵(sentinel) 进程,这些进程使用流言协议(gossipprotocols)来接收关于Master是否下线的信息,
并使用投票协议(agreement protocols)来决定是否执行自动故障迁移,以及选择哪个Slave作为新的Master。
工作原理:
1.三个定时监控任务:
1.1 每隔10s,每个S节点(哨兵节点)会向主节点和从节点发送info命令获取最新的拓扑结构
1.2 每隔2s,每个S节点会向某频道上发送该S节点对于主节点的判断以及当前Sl节点的信息,
同时每个Sentinel节点也会订阅该频道,来了解其他S节点以及它们对主节点的判断(做客观下线依据)
1.3 每隔1s,每个S节点会向主节点、从节点、其余S节点发送一条ping命令做一次心跳检测(心跳检测机制),来确认这些节点当前是否可达
2.主客观下线:
2.1主观下线:根据第三个定时任务对没有有效回复的节点做主观下线处理
2.2客观下线:若主观下线的是主节点,会咨询其他S节点对该主节点的判断,超过半数,对该主节点做客观下线
3.选举出某一哨兵节点作为领导者,来进行故障转移。选举方式:raft算法。每个S节点有一票同意权,哪个S节点做出主观下线的时候,
就会询问其他S节点是否同意其为领导者。获得半数选票的则成为领导者。基本谁先做出客观下线,谁成为领导者。
八、 顺序队列与循环队列
队列本身也是一种线性表,因而和线性表一样也有顺序和链式存储结构两种存储方式。
采用顺序存储结构实现的队列称为顺序队列;
采用链式存储结构实现的队列称为链队列。
1. 顺序队列中的溢出现象:
① "下溢"现象
当队列为空时,做出队运算产生的溢出现象。“下溢”是正常现象,常用作程序控制转移的条件。
② "真上溢"现象
当队列满时,做进栈运算产生空间溢出的现象。“真上溢”是一种出错状态,应设法避免。
③ "假上溢"现象
由于入队和出队操作中,头尾指针只增加不减小,致使被删元素的空间永远无法重新利用。当队列中实际的元素个数远远小于向量空间的规模时,
也可能由于尾指针已超越向量空间的上界而不能做入队操作。该现象称为"假上溢"现象。
2. 循环队列
为充分利用向量空间,克服"假上溢"现象的方法是:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。存储在其中的队列称为循环队列
网友评论