1、Redis?
- Redis是用C语言开发的一个开源的高性能键值对(key-value)内存数据库。
- 它提供五种数据类型来存储:字符串类型、散列类型、列表类型、集合类型、有序集合类型。
- 它是一种NoSQL数据库。
2、NoSQL?
- NoSQL,即Not-Only SQL(不仅仅是SQL),泛指非关系型的数据库。
- 关系型数据库?数据结构是一种有行有列的数据库。
- NoSQL数据库是为了解决高并发、高可用、高可扩展、大数据库存储问题而产生的数据库解决方案。
- NoSQL可以作为关系型数据库的良好补充,但是不能替代关系型数据库。
- 所有关系型数据库都是将数据存储到硬盘中的,而Redis这个NoSQL数据库是将数据存储到内存中的。
3、关系型和非关系型数据库的区别?
- 关系型数据库主要用来存储系统的业务数据。
- 非关系型数据库主要用来解决一些特殊情况下的存储问题,高并发、高可用、高可扩展、大数据库存储。
- 关系型数据库和非关系型数据库之间不是互斥的关系,而是互补的关系。
4、NoSQL数据库分类
4.1、键值(Key-Value)存储数据库
相关产品:Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley BD
典型应用:内容缓存,主要用于处理大量数据的高访问负载
数据模型:一系列键值对
优势:快速查询
劣势:存储的数据缺少结构化
4.2、列存储数据库
相关产品:Cassandra、HBase、Riak
典型应用:分布式的文件系统
数据模型:以列簇式存储,将同一列数据存在一起
优势:查找速度快,可扩展性强,更容易进行分布式扩展
劣势:功能相对局限
4.3、文档型数据库
相关产品:CouchDB、MongoDB
典型应用:Web应用(与Key-Value类似,Value是结构化的)
数据模型:一系列键值对
优势:数据结构要求不严格
4.4、图形(Graph)数据库
相关数据库:Neo4J、InfoGrid、Infinite Graph
典型应用:社交网络
数据模型:图结构
优势:利用图结构相关算法
劣势:需要对整个图做计算才能得出结果,不容易做分布式的集群方案
5、Redis的应用场景
- 内存数据库(登录信息、购物车信息、用户浏览记录等)
- 缓存服务器(商品数据、广告数据等等)(最多使用)
- 解决分布式集群架构中的session分离问题(session共享)
- 任务队列(秒杀、抢购、12306等)
- 支持发布订阅的消息模式
- 应用排行榜
- 网站访问统计
- 数据过去处理(可以精确到毫秒)
6、Redis数据类型
Redis中存储数据是通过key-value格式存储数据的,其中value可以定义五种数据类型:
- String(字符类型)
- Hash(散列类型)
- List(列表类型)
- Set(集合类型)
- SortedSet(有序集合类型,简称zset)
注意:在redis中的命令语句中,命令是可以忽略大小写的,而key是不忽略大小写的。
6.1、String类型
命令语法
赋值:SET key value
取值:GET key
取值并赋值:GETSET key value
递增数字(**应用场景:自增主键):INCR key
6.2、Hash类型(不过多关注)
6.3、List类型(有序)
命令语法
向列表左边增加元素:LPUSH key value [value ...]
向列表右边增加元素:RPUSH key valeu [value ...]
6.4、Set类型(去重)
命令语法
增加元素:SADD key member [member ...]
删除元素:SREM key member [member ...]
6.5、Zset类型(有序并去重)
应用-商品销售排行
需求:根据商品销售量对商品进行排行显示
思路:定义商品销售排行榜(sorted set 集合),Key为items:sellsort,分数为商品销售量
写入商品销售量:
商品编号1001的销售量是9,商品编号1002的销售量是10:ZADD items:sellsort 9 1001 10 1002
商品编号1001的销售量加1:ZINCRBY items:sellsort 1 1001
商品销售量前10名:ZRANGE items:sellsort 0 9 WITHSCORES
6.6、通用命令
6.6.1、ksys
作用:返回满足给定pattern的所有key
语法:keys pattern
redis 127.0.0.1:6379> keys mylist*
1) "mylist"
2) "mylist5"
3) "mylist6"
4) "mylist7"
5) "mylist8"
6.6.2、del
语法:DEL key
redis 127.0.0.1:6379> del test
(integer) 1
6.6.3、exists
作用:确认一个key是否存在
语法:exists key
6.6.4、expire
Redis在实际使用过程中更多的用做缓存,然而缓存的数据一般都是需要设置生存时间的,即到期后数据销 毁。
设置key的生存时间(单位:秒)key在多少秒后会自动删除,语法:EXPIRE key seconds
查看key剩余的生存时间,语法:TTL key
清除生存时间,语法:PERSIST key
生存时间设置单位为:毫秒,语法:PEXPIRE key milliseconds
7、Redis事务
7.1、Redis事务介绍
- Redis的事务是通过MULTI、EXEC、DISCARD和WATCH这四个命令来完成的。
- Redis的单个命令都是原子性的,所以这里确保事务性的对象是命令集合。
- Redis将命令集合序列化并确保处于同一事务的命令集合连续且不被打断的执行。
- Redis不支持回滚操作
7.2、事务命令
- 开启事务:multi
- 通过监听某个key,来设置条件:watch key
- 清除先前队列中的命令:discard
- 提交事务:exec
7.3、事务失败处理
-
Redis语法错误(可以理解为编译器错误)
-
Redis类型错误(可以理解为运行期错误)
-
Redis不支持事务回滚,为什么?
1、大多数事务失败是因为语法错误或者类型错误,这两种错误,在开发阶段都是可以预见的
2、Redis为了性能方面就忽略了事务回滚
8、Redis实现分布式锁
8.1、锁的处理
- 单应用中使用锁:单进程多线程 synchronize、lock
- 分布式应用中使用锁:多进程
8.2、分布式锁的实现方式
- 基于数据库的乐观锁实现分布式锁
- 基于zookeeper临时节点的分布式锁
- <u>基于Redis的分布式锁</u>
8.3、分布式锁的注意事项
- 互斥性:在任意时刻,只有一个客户端能持有锁
- 同一性:加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了
- 可重入性:即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁
8.4、实现分布式锁
8.4.1、获取锁
在SET命令中,有很多选项可用来修改命令的行为,以下是SET命令可用选项的基本语法。
redis 127.0.0.1:6379> SET KEY VALUE [EX seconds] [PX milliseconds] [NX|XX]
- EX seconds -设置指定的到期时间(以秒为单位)。
- PX milliseconds -设置指定的到期时间(以毫秒为单位)。
- NX -仅在键不存在时设置键。
- XX -只有在键已存在时才设置。
可使用setnx命令实现
public static boolean getlock(String lockKey, String requestId, int expireTime){
Long result = jedis.setnx(lockKey, requestId);
if(result == 1){
jedis.expire(lockKey, expireTime);
return true;
}
return false;
}
8.4.2、释放锁
可使用redis+lua脚本实现
public static boolean releaseLock(String lockKey, String requestId){
String script = "if redis.call('get', KEY[1]) -- ARGV[1] then return redis.call('del', KEY[1]) else return 0 end";
Object result = jedis.eval(script, Collection.singletonList(lockKey), Collections.singletonList(requestId));
if(result。equals(1L)){
return true;
}
return false;
}
9、Redis持久化方案
Redis是一个内存数据库,为了保证数据的持久性,它提供了两种持久化方案:
- RDB方式(默认)
- AOF方式
9.1、RDB方式
9.1.1、介绍
-
RDB是Redis默认采用的持久方式
-
RDB方式是通过快照(snapshotting)完成的,当符合一定条件时Redis会自动将内存中的数据进行快照并持久化到硬盘。
-
Redis会在指定情况下触发快照
- 符合自定义配置的快照规则
- 执行save或者bgsave命令
- 执行flushall命令
- 执行主从复制操作
-
在redis.conf中设置自定义快照规则
-
RDB持久化条件
格式:save <senonds> <changes>
示例:
save 900 1:表示15分钟(900秒)内至少1个键被更改则进行快照。
save 300 10:表示5分钟(200秒)内至少10个键被更改则进行快照。
save 60 10000:表示1分钟内至少10000个键被更改则进行快照。
可以配置多个条件(每行配置一个条件),每个条件之间是”或“的关系。
不使用RDB方式直接在配置文件中 save ""
-
配置dir指定rdb快照文件位置
# Not that you must specify a directory here, not a file name. dir ./
-
配置dbfilename指定rdb快照文件名称
# The filename where to dump the DB dbfilename dump.rdb
9.1.2、RDB快照的实现原理
-
快照过程
- Redis调用系统中的fork函数复制一份当前进程的副本(子进程)。
- 父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件。
- 当子进程写入完所有数据后会用该临时文件替换旧的RDB文件,至此,一次快照操作完成。
-
注意事项
- redis在进行快照的过程中不会修改RDB文件,只有快照结束后才会将旧的文件替换成新的,也就是说任务时候RDB文件都是完整的。
- 这就使得我们可以通过定时备份RDB文件来实现redis数据库的备份,RDB文件是经过压缩的二进制文件,占用的空间会小于内存中的数据,更利于传输。
9.1.3、RDB优缺点
- 缺点:使用RDB方式实现持久化,一点Redis异常退出,就会丢失最后一次快照以后更改的所有数据。这个时候我们就需要根据具体的应用场景,通过组合设置自动快照条件的方式来将可能发生的数据损失控制在能够接受的范围。如果数据相对来说比较重要,希望将损失降到最小,则可以使用AOF方式进行持久化。
- 优点:RDB可以最大化Redis的性能:父进程在保存RDB文件时间唯一要做的就是fork出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无序执行任何磁盘I/O操作。同时这个也是一个缺点,如果数据集比较大的时候,fork可能比较耗时,造成服务器在一段时间内停止处理客户端的请求。
9.2、AOF方式
9.2.1、介绍
-
默认情况下Redis没有开启AOF(append only file)方式的持久化
-
开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件,这一过程显然会降低Redis的性能,但大部分情况下这个影响是能够接受的,另外使用较快的硬盘可以提高AOF的性能。
-
可以通过redis.conf配置文件中的appendonly参数开启
appendonly yes
-
AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的
dir ./
-
默认的文件名是appendonly.aof,可以通过appendfilename参数修改
appendfilename appendonly.aof
网友评论