DeTechn Blog

Redis基础及高可用、高并发、集群相关知识

什么是Redis?

redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(列表)、set(集合)、zset(sorted set --有序集合)和hashs(哈希类型)
这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的.
在此基础上,redis支持各种不同方式的排序.与memcached一样,为了保证效率,数据都是缓存在内存中.
区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步.

使用Redis有哪些好处?

速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)
支持丰富数据类型,支持string,list,set,sorted set,hash
支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除

Redis解决秒杀/抢红包等高并发事务活动

秒杀开始前30分钟把秒杀库存从数据库同步到Redis Sorted Set
用户秒杀库存放入秒杀限制数长度的Sorted Set
秒杀到指定秒杀数后,Sorted Set不在接受秒杀请求,并显示返回标识
秒杀活动完全结束后,同步Redis数据到数据库,秒杀正式结束

Redis数据超过可用内存的处理方式

1、修改redis.conf中的maxmemory-policy选项,设置删除redis键的淘汰规则
2、加内存
3、缩短(或设置)数据过期时间,以释放内存
4、redis集群
如果redis数据中,存的是关键数据,怕丢失的数据,那么,redis数据占用的内存,不要超过内存大小的70%(保险起见不要超过55%),以免内存不足!不要期望什么内存淘汰策略!它所做的居然是删数据!
如果数据是不怕丢的缓存数据,那么可以在redis.conf里,配置如下两项,进行内存数据淘汰(其实是删除)

什么是高可用架构?

在介绍高可用架构的方案之前,先说一下什么是高可用架构,高可用架构应具备但不限于以下特征:
主从切换
很好理解,当其中一台机器的服务宕机后,对于服务调用者来说,能够迅速的切换到其他可用服务,从服务升级为主服务,这种切换速度应当控制在秒级别(几秒钟)。
当宕机的服务恢复之后,自动变为从服务,主从服务角色切换。主从切换一定是要付出代价的,所以当主服务恢复之后,也就不再替换现有的主服务。
负载均衡
当服务的请求量比较高的时候,一台服务不能满足需求,这时候需要多台机器提供同样的服务,将所有请求分发到不同机器上。
高可用架构中应该具有丰富的负载均衡策略和易调节负载的方式。
甚至可以自动化智能调节,例如由于机器性能的原因,响应时间可能不一样,这时候可以向性能差的机器少一点分发量,保证各个机器响应时间的均衡。
易横向扩展
当用户量越来越多,已有服务不能承载更多的用户的时候,便需要对服务进行扩展,扩展的方式最好是不触动原有服务,对于服务的调用者是透明的。

Redis 高可用

高可用架构一般都要具备主从复制\切换、负载均衡、易于扩展等特性,如果节点较少可以直接使用Redis集群,Redis集群具备这些特性,只要有一半以上的节点正常就能提供服务;如果规模较大的时候,就可以引入sentinel“哨兵”组件,它能提供监控、提醒、自动故障迁移等服务

Redis 高并发

高并发下主要考虑的是Redis集群方案,把流量分散到不同的Redis机器中去。
Redis集群可以从横向和纵向两个方面考虑,增强整体的可用性。
横向可以从分库剥离,负载均衡,一致性算法方面进行考虑
纵向可以从副本集,持久化,灾备等方面进行考虑
(即横向集群方案做高并发,纵向做高可用)

Redis应用之利用

redis高效统计访问量及访问的用户(计数)

原理:利用setbit方法,设置一个二进制每一位都为0的变量如usercount,通过算法给每一个访客一个唯一的数字ID标识,然后给usercount设置该用户ID位为1即可,通过bitcount usercount命令获取usercount有多少个1即为访客总数。通过这个方法保存1亿个用户的访问数据(总访问量和来访的用户)只需要不足10m的空间,而且非常高效。 使用方法如下:

set usercount 0
>>> OK
bitcount usercount
>>> 2  # 0的二进制值为0110000,所以为2
setbit usercount 2 0
setbit usercount 3 0  # 以上两句设置usercount的第2、3位为0,此时二进制值为 00000000
setbit usercount 4999 1  # 假设ID为4999的用户来访,设置usercount 的第4999位为1
setbit usercount 3582 1  # 假设ID为3582的用户来访,设置usercount 的第3582位为1
bitcount usercount
>>> 2  # 此时共有4999、3582两个访客,因此总数为2
getbit usercount 4999
>>> 1  # 获取ID为4999的用户的来访状态,如果值为1,则是访客,如果是0则是非访客

redis 和 mysql 的区别?

redis 是内存数据库,数据保存在内存中,速度快。
mysql 是关系型数据库,持久化存储,存放在磁盘里面,功能强大。检索的话,会涉及到一定的 IO,数据访问也就慢。
一般需要永久存储的数据使用MySQL,比如用户信息,文章等
而临时数据或者经常访问的数据就会使用redis,比如用户的session/排行榜/访问计数/Pub Sub 构建实时消息系统/缓存等

Memcache与Redis的区别都有哪些?

1)、存储方式 Memecache把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。Redis有部份存在硬盘上,这样能保证数据的持久性。
2)、数据支持类型 Memcache对数据类型支持相对简单。 Redis有复杂的数据类型。
3)、使用底层模型不同 它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。Redis直接自己构建了VM机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。

Redis常见的性能问题和解决方法

1.Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化。
2.如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。
3.为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内。
4.尽量避免在压力较大的主库上增加从库
5.为了Master的稳定性,主从复制不要用图状结构,用单向链表结构更稳定,即主从关系为:Master<--Slave1<--Slave2<--Slave3.......,这样的结构也方便解决单点故障问题,实现Slave对Master的替换,也即,如果Master挂了,可以立马启用Slave1做Master,其他不变。

mySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据

相关知识:redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略(回收策略)。redis 提供 6种数据淘汰策略:
volatile-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的并发竞争问题如何解决?

Redis为单进程单线程模式,采用队列模式将并发访问变为串行访问。Redis本身没有锁的概念,Redis对于多个客户端连接并不存在竞争,但是在Jedis客户端对Redis进行并发访问时会发生连接超时、数据转换错误、阻塞、客户端关闭连接等问题,这些问题均是由于客户端连接混乱造成。对此有2种解决方法:
1.客户端角度,为保证每个客户端间正常有序与Redis进行通信,对连接进行池化,同时对客户端读写Redis操作采用内部锁synchronized。
2.服务器角度,利用setnx实现锁。
注:对于第一种,需要应用程序自己处理资源的同步,可以使用的方法比较通俗,可以使用synchronized也可以使用lock;第二种需要用到Redis的setnx命令,但是需要注意一些问题。

Redis如果运行过程中崩溃了怎么办?

这个问题面试官想问的是Redis的数据保障的方法,不然崩溃了除了重启还能怎么办?
Redis有提供数据持久化的功能,一种是快照,一种是AOF。
快照是在某一个时间点将所有数据写入到磁盘中,AOF是将被执行的命令复制到硬盘中,快照的文件体积要比AOF的文件体积小。前者在恢复时速度比后者快,但是因为是间隔持久化,所以会有一定量的数据丢失。后者因为是实时写入的,所以数据的完整性比较好,如果丢失的话一般也就丢失一秒的数据。
其次需要做主从复制,这样一份数据可以保存在多台服务器上,且可以避免Redis崩溃到重启完成这段时间内无法提供正常服务,同时从服务器可以分担主服务器的读压力。

Redis集群

Redis集群创建步骤是
1、在至少3台服务器上安装redis服务
2、分别修改这些服务器上redis的配置文件并确保它们可以互相访问,然后启动它们
3、使用Redis 官方提供的redis-trib.rb工具的create命令创建集群

Redis集群的工作原理

redis cluster在设计的时候,就考虑到了去中心化,去中间件,也就是说,集群中的每个节点都是平等的关系,都是对等的,每个节点都保存各自的数据和整个集群的状态。每个节点都和其他所有节点连接,而且这些连接保持活跃,这样就保证了我们只需要连接集群中的任意一个节点,就可以获取到其他节点的数据。
Redis 集群没有并使用传统的一致性哈希来分配数据,而是采用另外一种叫做哈希槽 (hash slot)的方式来分配的。redis cluster 默认分配了 16384 个slot,当我们set一个key 时,会用CRC16算法来取模得到所属的slot,然后将这个key 分到哈希槽区间的节点上,具体算法就是:CRC16(key) % 16384。所以我们在测试的时候看到set 和 get 的时候,直接跳转到了7000端口的节点。
Redis 集群会把数据存在一个 master 节点,然后在这个 master 和其对应的salve 之间进行数据同步。当读取数据时,也根据一致性哈希算法到对应的 master 节点获取数据。只有当一个master 挂掉之后,才会启动一个对应的 salve 节点,充当 master 。
需要注意的是:必须要3个或以上的主节点,否则在创建集群时会失败,并且当存活的主节点数小于总节点数的一半时,整个集群就无法提供服务了。

悲观锁和乐观锁区别,乐观锁适用于什么情况

悲观锁,每次访问数据的时候都觉得会有别人修改它,所以每次拿数据时都会上锁,确保在自己使用的过程中不会被他人访问。乐观锁每次拿数据的时候都不会上锁,只在更新数据的时候去判断该数据是否被别人修改过。
大多数的关系数据库写入操作都是基于悲观锁,缺点在于如果持有锁的客户端运行的很慢,那么等待解锁的客户端被阻塞的时间就越长。Redis的事务是基于乐观锁的机制,不会在执行WATCH命令时对数据进行加锁,只是会在数据已经被其他客户端抢先修改了的情况下,通知执行WATCH命令的客户端。
乐观锁适用于读多写少的情况,因为在写操作比较频繁的时候,会不断地retry,从而降低性能。

MVCC

在并发读写数据库时,读操作可能会不一致的数据(脏读)。为了避免这种情况,需要实现数据库的并发访问控制,最简单的方式就是加锁访问。
由于,加锁会将读写操作串行化,所以不会出现不一致的状态。但是,读操作会被写操作阻塞,大幅降低读性能。
而其优化的手段就是,在进行写操作时,将数据copy一份,不会影响原有数据,然后进行修改,修改完成后原子替换掉旧的数据,而读操作只会读取原有数据。
通过这种方式实现写操作不会阻塞读操作,从而优化读效率。
MVCC全称是Multi-Version Concurrent Control,即多版本并发控制。
在MVCC协议下每个读操作会看到一个一致性的snapshot,并且可以实现非阻塞的读。MVCC允许数据具有多个版本,这个版本可以是时间戳或者是全局递增的事务ID,
在同一个时间点,不同的事务看到的数据是不同的。

当前页面是本站的「Google AMP」版。查看和发表评论请点击:完整版 »