- Redis介绍
- 什么是Redis
Redis是一种key-value形式的NoSQL内存数据库,由ANSI C编写,遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。Redis最大的特性是它会将所有数据都放在内存中,所以读写速度性能非常好
注:Redis与Memcached的比较:
1. Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储。
2.Redis支持数据的备份,即master-slave模式的数据备份。
3. Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。
-
- 为什么使用redis
数据存在内存中,Redis交换数据快,所以在服务器中常用来存储一些需要频繁调取的数据,这样可以大大节省系统直接读取磁盘来获得数据的I/O开销,更重要的是可以极大提升速度。
-
- Redis 的优缺点
- 优点
- Redis 的优缺点
1.读写性能优异,速度快,因为数据存在内存中。
2.支持数据持久化,支持AOF和RDB两种持久化方式(由于Redis的数据都存放在内存中,如果没有配置持久化,redis重启后数据就全丢失了,于是需要开启redis的持久化功能,将数据保存到磁 盘上,当redis重启后,可以从磁盘中恢复数据。redis提供两种方式进行持久化,一种是RDB持久化:指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。还有一种是AOF持久化:以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。)
3.支持主从复制,主机会自动将数据同步到从机
4.数据结构丰富:除了支持string类型的value外还支持string、hash、set、sortedset、list等数据结构。
-
-
- 缺点
-
- 数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。
- 主从同步,如果主机宕机,宕机前有一部分数据没有同步到从机,会导致数据不一致。
- 主从同步,数据同步会有延迟。
- 对事务的支持
- Redis的安装
- 安装命令:
配置云源:https://blog.csdn.net/chavo0/article/details/51939362
yum install gcc tcl
wget http://download.redis.io/releases/redis-5.0.0.tar.gz
tar xzf redis-5.0.0.tar.gz
mv redis-5.0.0 redis
cd redis
make
make install PREFIX=/usr/local/redis
- 拷贝默认配置文件
cp /usr/local/redis/redis.conf ./
- 修改默认配置文件
Vim redis.conf
修改redis.conf文件,将daemonize改为yes
- 后台启用
./redis-server redis.conf
验证是否启动成功
Ps -ef|grep redis
注:远程客户端连接不上redis 服务
- 注释掉redis.window.conf文件中的bind属性设置。
- 把protected-mode属性设置no
- 重启redis
- Redis客户端
- redis 自带的客户端
-
- Redis可视化客户端
-
- Jedis客户端
Redis不仅是使用命令来操作,现在基本上主流的语言都有客户端支持,比如java、C、C#、C++、php、Node.js、Go等。
在官方网站里列一些Java的客户端,有Jedis、Redisson、Jredis、JDBC-Redis、等其中官方推荐使用Jedis和Redisson。 在企业中用的最多的就是Jedis。
- Redis数据类型
- String
String是最简单的类型,一个key对应一个value,value存储最大数据量为512M
-
-
- jedis操作方法
-
1.set(key, value):设置指定key的值
2.get(key):获取指定key的值
3.getset(key, value):将给定key的值设置为value,并返回key的旧值
4.del(key):删除
5.incr(String key)将key中存储的数字值加一
6.incrby(key, integer):名称为key的string增加integer
7.decr(key):名称为key的string减1操作
8. decrby(key, integer):名称为key的string减少integer
9.setex(key, time, value) time 单位为秒
-
-
- 应用场景
-
1.计数器:如 主键自增,统计网站访问数量、当前在线人数、微博数、粉丝数等
-
- Hash
- Hash类型介绍
- Hash
hash叫散列类型,它提供了字段和字段值的映射,如图
-
-
- Jedis操作方法
-
- hset(key, field, value):向名称为key的hash中添加元素field<—>value
- hget(key, field):返回名称为key的hash中field对应的value
- hdel(key, field):删除名称为key的hash中键为field的域
- hincrby(key, field, integer):将名称为key的hash中field的value增加integer
注:HSET命令不区分插入和更新操作,当执行插入操作时HSET命令返回1,当执行更新操作时返回0。
-
-
- 应用场景
-
- 存储、读取、修改用户属性(name,age,pwd等)
-
- List
- Arraylist和linkedlist的区别
- List
1、ArrayList使用数组方式存储数据,所以根据索引查询数据速度快,而新增或者删除元素时需要涉及到位移操作,所以比较慢。
2、LinkedList使用双向链表方式存储数据,每个元素都记录前后元素的指针,所以插入、删除数据时只是更改前后元素的指针指向即可。速度非常快,然后通过下标查询元素需要从头开始索引,所以比较慢。
Redis的list是采用来链表来存储的,所以对于redis的list数据类型的操作,是操作list的两端数据来操作的。
-
-
- Jedis 操作方法
-
1 rpush(key, value):在名称为key的list尾添加一个值为value的元素
2 lpush(key, value):在名称为key的list头添加一个值为value的 元素
3 lpop(key):返回并删除名称为key的list中的首元素
4 rpop(key):返回并删除名称为key的list中的尾元素
5 lrange(key, start, end):返回名称为key的list中start至end之间的元素(下标从0开始,下同)
6 lrem(key, count, value):删除count个名称为key的list中值为value的元素。count为0,删除所有值为value的元素,count>0 从头至尾删除count个值为value的元素,count<0从尾到头删除|count|个值为value的元素。
-
-
- 应用场景
-
- 消息队列,以完成多程序之间的消息交换。可以利用List的PUSH将任务存在List中(生产者),然后工作线程再用POP将任务取出(消费者)
-
- Set
无序、不可重复
-
-
- Jedis操作方法
-
1. sadd(key, member):向名称为key的set中添加元素member
2. srem(key, member) :删除名称为key的set中的元素member
3. sismember(key, member) :测试member是否是名称为key的set的元素
4. smembers(key) :返回名称为key的set的所有元素
-
-
- 运算命令
-
- 集合的差集运算 A-B
sdiff(key1,key2);
属于A并且不属于B的元素构成的集合。
- 集合的交集运算 A ∩ B
Sinter(key1,key2)
属于A且属于B的元素构成的集合。
- 集合的并集运算 A ∪ B
Sunion(key1,key2)
-
-
- 应用场景
-
- 获取某段时间所有数据去重值
- 利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,自己独有的喜好等功能
- Sorted set
Sorted set是有序集合,可排序的,但是唯一。
-
-
- Jedis 操作方法
-
1 zadd(key, score, member):向名称为key的zset中添加元素member,score用于排序。如果该元素已经存在,则根据score更新该元素的顺序。
2 zrem(key, member) :删除名称为key的zset中的元素member
3 zscore(key, element):返回名称为key的zset中元素element的score
获得排名在某个范围的元素列表
4 zrange(key, start, end):返回名称为key的zset(元素已按score从小到大排序)中的index从start到end的所有元素
5 zrevrange(key, start, end):返回名称为key的zset(元素已按score从大到小排序)中的index从start到end的所有元素
获取元素的排名
6 zrank(key, member) :返回名称为key的zset(元素已按score从小到大排序)中member元素的rank(即index,从0开始),若没有member元素,返回“nil”
7 zrevrank(key, member) :返回名称为key的zset(元素已按score从大到小排序)中member元素的rank(即index,从0开始),若没有member元素,返回“nil”
-
-
- 应用场景
-
- 排行榜
- redis的过期策略以及内存淘汰机制
redis采用的是定期删除+惰性删除策略。
-
- 定期删除+惰性删除是如何工作的?
定期删除,redis默认每个100ms检查,是否有过期的key,有过期key则删除。需要说明的是,redis不是每个100ms将所有的key检查一次,而是随机抽取进行检查(如果每隔100ms,全部key进行检查,redis岂不是卡死)。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。
于是,惰性删除派上用场。也就是说在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除。
内存淘汰策略
-
- 常用的淘汰算法:
FIFO:First In First Out,先进先出。判断被存储的时间,离目前最远的数据优先被淘汰。
LRU:Least Recently Used,最近最少使用。判断最近被使用的时间,目前最远的数据优先被淘汰。
LFU:Least Frequently Used,最不经常使用。在一段时间内,数据被使用次数最少的,优先被淘汰。
-
- Redis提供的淘汰策略:
1.noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
2.allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。3.allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。4.volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。这种情况一般是把redis既当缓存,又做持久化存储的时候才用。不推荐
5.volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
6.volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。
配置文件配置策略:# maxmemory-policy volatile-lru
- Redis的持久化
- Redis的持久化策略
- Rdb
默认情况下,是快照rdb的持久化方式,将内存中的数据以快照的方式写入二进制文件中,默认的文件名是dump.rdb
redis.conf配置:
save 900 1 save 300 10 save 60 10000 |
默认是如上配置:900秒之内,如果超过1个key被修改,则发起快照保存;
300秒内,如果超过10个key被修改,则发起快照保存
1分钟之内,如果1万个key被修改,则发起快照保存
- Rdb问题
一旦redis非法关闭,那么会丢失最后一次持久化之后的数据。
如果数据不重要,则不必要关心。
如果数据不能允许丢失,那么要使用aof方式。
- Aof
Redis默认是不使用该方式持久化的。Aof方式的持久化,是操作一次redis数据库,则将操作的记录存储到aof持久化文件中。
配置方式:启动aof持久化的方式
appendonly yes |
- Redis的主从复制
Redis虽然读取写入的速度都特别快,但是也会产生读压力特别大的情况。为了分担读压力,Redis支持主从复制
主从复制:主节点负责写数据,从节点负责读数据,主节点定期把数据同步到从节点保证数据的一致性
-
- Redis主从拓扑
a)一主一从:用于主节点故障转移从节点,当主节点的“写”命令并发高且需要持久化,可以只在从节点开启AOF(主节点不需要),这样即保证了数据的安全性,也避免持久化对主节点的影响
b)一主多从:针对“读”较多的场景,“读”由多个从节点来分担,但节点越多,主节点同步到多节点的次数也越多,影响带宽,也加重主节点的稳定
c)树状主从:一主多从的缺点(主节点推送次数多压力大)可用些方案解决,主节点只推送一次数据到从节点B,再由从节点B推送到C,减轻主节点推送的压力。
- Redis其他概念
8.1Redis 管道概念
一次请求/响应服务器能实现处理新的请求即使旧的请求还未被响应。这样就可以将多个命令发送到服务器,而不用等待回复,最后在一个步骤中读取该答复。这就是管道。
管道与非管道执行过程对比
- 非管道:
例如下面是4个命令序列执行情况:
客户端和服务器通过网络进行连接。这个连接可以很快(loopback接口)或很慢(建立了一个多次跳转的网络连接)。无论网络延如何延时,数据包总是能从客户端到达服务器,并从服务器返回数据回复客户端。
这个时间被称之为 RTT (Round Trip Time - 往返时间). 当客户端需要在一个批处理中执行多次请求时很容易看到这是如何影响性能的(例如添加许多元素到同一个list,或者用很多Keys填充数据库)。例如,如果RTT时间是250毫秒(在一个很慢的连接下),即使服务器每秒能处理100k的请求数,我们每秒最多也只能处理4个请求。
2.管道:
局限性:
- 鉴于Pipepining发送命令的特性,Redis服务器是以队列来存储准备执行的命令,而队列是存放在有限的内存中的,所以不宜一次性发送过多的命令。如果需要大量的命令,可分批进行,效率不会相差太远滴,总好过内存溢出
- 由于pipeline的原理是收集需执行的命令,到最后才一次性执行。所以无法在中途立即查得数据的结果(需待pipelining完毕后才能查得结果),这样会使得无法立即查得数据进行条件判断(比如判断是非继续插入记录)。
8.2Redis事务
事务的生命周期:
1. 事务的创建:使用MULTI开启一个事务
2. 加入队列:在开启事务的时候,每次操作的命令将会被插入到一个队列中,同时这个命令并不会被真的执行
3. EXEC命令进行提交事务
常用的关于事务的命令有:
1. MULTI:使用该命令,标记一个事务块的开始,通常在执行之后会回复OK,(但不一定真的OK),这个时候用户可以输入多个操作来代替逐条操作,redis会将这些操作放入队列中。
2. EXEC:执行这个事务内的所有命令
3. DISCARD:放弃事务,即该事务内的所有命令都将取消
4. WATCH:监控一个或者多个key,如果这些key在提交事务(EXEC)之前被其他用户修改过,那么事务将执行失败,需要重新获取最新数据重头操作(类似于乐观锁)。
5. UNWATCH:取消WATCH命令对多有key的监控,所有监控锁将会被取消。
最基本的事务操作命令实例:
使用事务时可能会遇上以下两种错误:
- 执行之前
说明:错误命令在我输入的时候就已经报错了,也就是说这个条错误命令在进入队列的时候redis就已经知道这是一条错误命令,这样,整个事务的命令将全部失败
- 执行之后
说明:如果这个错误命令在入队的时候并没有报错,而是在执行的时候出错了,那么redis默认跳过这个命令执行后续命令。
- watch 关键字说明
被 WATCH 的键会被监视,并会发觉这些键是否被改动过了。 如果有至少一个被监视的键在 EXEC 执行之前被修改了, 那么整个事务都会被取消, EXEC 返回nil-reply来表示事务已经失败。
如:客户端1
客户端2
总结:
1. 单独的隔离操作:事务中的所有命令会被序列化、按顺序执行,在执行的过程中不会被其他客户端发送来的命令打断
2. 不保证原子性:redis中的一个事务中如果存在命令执行失败,那么其他命令依然会被执行,没有回滚机制
- redis 应用常见问题
9.1缓存和数据库双写一致性问题
分析:一致性问题是分布式常见问题,还可以再分为最终一致性和强一致性。数据库和缓存双写,就必然会存在不一致的问题。答这个问题,先明白一个前提。就是如果对数据有强一致性要求,不能放缓存。我们所做的一切,只能保证最终一致性。另外,我们所做的方案其实从根本上来说,只能说降低不一致发生的概率,无法完全避免。因此,有强一致性要求的数据,不能放缓存。
采取正确更新策略,先更新数据库,再删缓存。其次,因为可能存在删除缓存失败的问题,提供一个补偿措施。
9.2缓存雪崩问题
即缓存同一时间大面积的失效,这个时候又来了一波请求,结果请求都怼到数据库上,从而导致数据库连接异常。
9.3缓存击穿问题
缓存穿透,即黑客故意去请求缓存中不存在的数据,导致所有的请求都怼到数据库上,从而数据库连接异常。
9.4缓存的并发竞争问题
准备一个分布式锁,大家去抢锁,抢到锁就做set操作即可