Redis简介
REmote DIctionary Server(Redis) 是一个由SalvatoreSanfilippo写的key-value存储系统。 Redis是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。 它通常被称为数据结构服务器,因为值(value)可以是字符串(String), 哈希(Map), 列表(list), 集合(sets) 和有序集合(sorted sets)等类型。
Redis五大基本数据类型
Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
String(字符串)
string 是 redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。
string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。
string 类型是 Redis 最基本的数据类型,string 类型的值最大能存储 512MB。
常用命令:set、get、decr、incr、mget等。
注意:一个键最大能存储512MB。
Hash(哈希)
Redis hash 是一个键值(key=>value)对集合;是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
每个 hash 可以存储 232 -1 键值对(40多亿)。
常用命令:hget、hset、hgetall等。
应用场景:存储一些结构化的数据,比如用户的昵称、年龄、性别、积分等,存储一个用户信息对象数据。
List(列表)
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
list类型经常会被用于消息队列的服务,以完成多程序之间的消息交换。
常用命令:lpush、rpush、lpop、rpop、lrange等。
列表最多可存储 232 - 1 元素 (4294967295, 每个列表可存储40多亿)。
Set(集合)
Redis的Set是string类型的无序集合。和列表一样,在执行插入和删除和判断是否存在某元素时,效率是很高的。集合最大的优势在于可以进行交集并集差集操作。Set可包含的最大元素数量是4294967295。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
zset(sorted set:有序集合)
Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
zset的成员是唯一的,但分数(score)却可以重复。
sorted set是插入有序的,即自动排序。
常用命令:zadd、zrange、zrem、zcard等。
当你需要一个有序的并且不重复的集合列表时,那么可以选择sorted set数据结构。
Redis配置文件常用参数及其默认值
(1)daemonize no
Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程
(2)pidfile /var/run/redis.pid
当Redis以守护进程方式运行时,Redis默认会把pid写入/var/run/redis.pid文件,可以通过pidfile指定
(3)port 6379
指定Redis监听端口,默认端口为6379
如果指定0端口,表示Redis不监听TCP连接
(4)bind 127.0.0.1
绑定的主机地址
可以绑定单一接口,如果没有绑定,所有接口都会监听到来的连接
(5)timeout 0
当客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能
(6)loglevel verbose
指定日志记录级别,Redis总共支持四个级别:debug、verbose、notice、warning,默认为verbose
(7)logfile stdout
日志记录方式,默认为标准输出,如果配置为redis为守护进程方式运行,而这里又配置为标准输出,则日志将会发送给/dev/null
(8)databases 16
设置数据库的数量,默认数据库为0,可以使用select
dbid是从0到‘databases’-1的数目
Redis数据持久化
RDB:
Redis会创建(fork)单独的一个子进程来进行持久化操作,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。这个过程主进程不进行任何IO操作,这就确保了Redis的性能。
如果需要进行大规模的数据恢复,且对于数据恢复的完整性不是非常敏感,那么RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。
save与bgsave:
1.save触发方式
该命令会阻塞当前Redis服务器,执行save命令期间,Redis不能处理其他命令,直到RDB过程完成为止。
执行完成时候如果存在老的RDB文件,就把新的替代掉旧的。我们的客户端可能都是几万或者是几十万,这种方式显然不可取。
2.bgsave触发方式
执行该命令时,Redis会在后台异步进行快照操作,快照同时还可以响应客户端请求.
具体操作是Redis进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短。基本上 Redis 内部所有的RDB操作都是采用 bgsave 命令。
RDB配置参数:
(1)
save 900 1
save 300 10
save 60 10000
指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合
表示 900秒(15分钟)内有1个更改
300秒(5分钟)内有10个更改
60秒内有10000个更改
满足三个条件中的任意一个,即将数据从内存同步到数据文件
(2)rdbcompression yes
指定存储至本地数据库时是否压缩数据,默认为yes,Redis采用LZF压缩,如果为了节省CPU时间,可以关闭该选项,但会导致数据库文件变的巨大
(3)rdbchecksum yes
默认值是yes。在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能
(4)stop-writes-on-bgsave-error yes
默认值为yes。当启用了RDB且最后一次后台保存数据失败,Redis是否停止接收数据。这会让用户意识到数据没有正确持久化到磁盘上,否则没有人会注意到灾难(disaster)发生了。如果Redis重启了,那么又可以重新开始接收数据了
(5)dbfilename dump.rdb
指定本地数据库文件名,默认值为dump.rdb
(6)dir ./
工作目录.
指定本地数据库存放目录,文件名由上一个dbfilename配置项指定
这里只能指定一个目录,不能指定文件名
AOF:
全量备份总是耗时的,有时候我们提供一种更加高效的方式AOF,工作机制很简单,redis会将每一个收到的写命令都通过write函数追加到文件中。
通俗的理解就是日志记录。
与hadoop的持久化操作类似,hadoop的数据持久化是通过对数据进行操作后,将操作日志写进edits文件,由secondarynamenode定时将edits文件与存储hadoop数据快照的fsimage文件进行合并,生成新的fsimage,这样既保证了数据的持久性又不会影响namenode的性能。
redis也是类似,通过fork出一个子进程,将redis的操作日志写进appendonly.aof文件中,以保证即使服务器宕机也能通过appendonly.aof对rdb文件进行恢复。
AOF三种触发机制
(1)每修改同步always:同步持久化 每次发生数据变更会被立即记录到磁盘 性能较差但数据完整性比较好
(2)每秒同步everysec:异步操作,每秒记录 如果一秒内宕机,有数据丢失
(3)不同no:从不同步
AOF配置参数:
(1)appendonly no
指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。
因为redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no
(2)appendfsync everysec
指定更新日志条件,共有3个可选值:
1.no:表示等操作系统进行数据缓存同步到磁盘(快)
2. always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全)
3.everysec:表示每秒同步一次(折衷,默认值)
(3)appendfilename appendonly.aof
指定更新日志文件名,默认为appendonly.aof
(4)no-appendfsync-on-rewrite
是否在后台写时同步单写,默认值no(表示需要同步).这里的后台写,表示后台正在重写文件.no表示新的主进程的set操作会被阻塞掉,而yes表示新的主进程的set不会被阻塞,待整个后台写完成之后再将这部分set操作同步到aof文件中。但这可能会存在数据丢失的风险(机率很小),如果对性能有要求,可以设置为yes,仅在后台写时会异步处理命令.
(5)auto-aof-rewrite-percentage aof
文件增长比例,指当前aof文件比上次重写的增长比例大小。aof重写即在aof文件在一定大小之后,重新将整个内存写到aof文件当中,以反映最新的状态(相当于bgsave)。这样就避免了,aof文件过大而实际内存数据小的问题(频繁修改数据问题).
(6)auto-aof-rewrite-min-size aof
文件重写最小的文件大小,即最开始aof文件必须要达到这个文件时才触发,后面的每次重写就不会根据这个变量了(根据上一次重写完成之后的大小).此变量仅初始化启动redis有效.如果是redis恢复时,则lastSize等于初始aof文件大小.
(7)aof-load-truncated yes
指redis在恢复时,会忽略最后一条可能存在问题的指令。默认值yes。即在aof写入时,可能存在指令写错的问题(突然断电,写了一半),这种情况下,yes会log并继续,而no会直接恢复失败.
Redis 在Linux下基本操作
安装Redis或者下载Redis镜像,这里使用镜像方式
命令:Docker pull redis:3.0
添加本地redis配置文件夹
mkdir /opt/module/configs/redis-config
mkdir /opt/module/configs/redis-config/data
接着用镜像生成容器并配置容器卷
docker run -p 6379:6379 --name redis -v /opt/module/configs/redis-config/redis.conf:/etc/redis/redis.conf -v /opt/module/configs/redis-config/data:/data -d redis:3.0 redis-server /etc/redis/redis.conf
需要注意的是如果以这种指定redis.conf配置文件方式开启redis,必须设置 daemonize no,否则redis会在容器中以守护进程的方式后台运行,docker会自动关闭该容器
Redis事务:
Redis事务相关命令:
MULTI :开启事务,redis会将后续的命令逐个放入队列中,然后使用EXEC命令来原子化执行这个命令系列。
EXEC:执行事务中的所有操作命令。
DISCARD:取消事务,放弃执行事务块中的所有命令。
WATCH:监视一个或多个key,如果事务在执行前,这个key(或多个key)被其他命令修改,则事务被中断,不会执行事务中的任何命令。
UNWATCH:取消WATCH对所有key的监视。
但是redis的事务不知支持回滚,事务更像是一个任务队列,彼此之间的成功与否互不影响。
严格的说Redis的命令是原子性的,而事务是非原子性的,我们要让Redis事务完全具有事务回滚的能力,需要借助于命令WATCH来实现。
Redis使用WATCH命令来决定事务是继续执行还是回滚,那就需要在MULTI之前使用WATCH来监控某些键值对,然后使用MULTI命令来开启事务,执行对数据结构操作的各种命令,此时这些命令入队列。
当使用EXEC执行事务时,首先会比对WATCH所监控的键值对,如果没发生改变,它会执行事务队列中的命令,提交事务;如果发生变化,将不会执行事务中的任何命令,同时事务回滚。当然无论是否回滚,Redis都会取消执行事务前的WATCH命令。
SpringBoot整合Redis
接着就可以使用redis了。
RedisTemplate提供了对应的ops操作五大Redis数据类型API,可以实现对应五种数据类型的基本操作。
但无论是哪种数据类型的操作,数据存入Redis数据库里后都是以Bytes数组的方式,Map的KV都是如此。如果我们用对应类型的反序列化器对数据进行操作那么并不会影响使用,但是如果我们需要在Redis里来直接对数据进行操作,那么我们将看到的都会是无可读性的Bytes数组。
这是因为RedisTemplate默认使用的是JDK自带的JdkSerializationRedisSerializer,还需要被序列化的类实现Serializer接口。
Spring也提供了StringRedisTemplate为我们实现String类型的序列化操作,通过该Template,字符串类型的数据会以可视化字符串的形式存储在Redis中,但是只能存储String类型。
点开它的实现,发现它也只是继承并修改了了RedisTemplate的序列化器。
SpringBoot为我们注入了RedisTemplate,我们也可以选择通过自定义RedisConfig @Bean的方式重写RedisTemplate的注入,来修改例如序列化与反序列化器的配置。
仅仅是这样我们就实现了类似StringRedisTemplate的自定义RedisTemplate。
也可以设置JSON格式的序列化方式
1,用StringRedisSerializer进行序列化的值,在Java和Redis中保存的内容是一样的
2,用Jackson2JsonRedisSerializer进行序列化的值,在Redis中保存的内容,比Java中多了一对双引号。
3,用JdkSerializationRedisSerializer进行序列化的值,对于Key-Value的Value来说,是在Redis中是不可读的。
事务:
在spring中要使用Redis注解式事务,首先要设置RedisTemplate的enableTransactionSupport属性为true,然后配置一个jdbc的事务管理器。
这里有一点非常重要,一旦这样配置,所有使用这个template的redis操作都必须走注解式事务,要不然会导致连接一直占用,不关闭。