Redis
一. 什么是Redis?
Redis是一套分布式高速缓存系统.
Redis与MongoDB,MemCache都是属于NoSQL思想的实现,称之为非关系型数据库.
二. 为什么需要Redis?
过去是单机型数据库的天下,各大数据库提供商都在努力提高单机型数据库的效率与安全性.其中Oracle和SQL Server以及MySQL更是其中的佼佼者.
随着互联网产业的高速发展,传统的数据库容量不断增大,并发读写量不断提高,以下三个方面的问题出现:
- 数据量过大(分表分库)
- 读写次数过多(读写分离)
三. Redis有什么用?
传统的关系型数据库每秒中写入大概23次,读稍微多一点.Redis大约每秒写8w次,读11w次.
关系型数据库保存数据以表形式,对字段类型进行限制,Redis使用KV保存方式,值的类型更加多元化.
Redis为系统提供更高速,更多元,更实时的数据.
四. Redis的特点
1. 支持数据持久化
可以将缓存在内存中的数据保存在磁盘中,重启后仍然可以使用数据.
2. 数据类型多元化
不仅提供简单的KV形式,还有提供list,set,zset,hash等数据结构的储存.
3. 支持数据备份
Master – Slave模式数据备份.
五. CAP理论
1.概念
1.1) Consistency(一致性)
数据一致更新,所有数据变动都是同步的
1.2) Availability(可用性)
好的响应性能
1.3) Partition tolerance(分区容忍性)
可靠性
2.总结
2.1任何分布式系统只可同时满足二点,没法三者兼顾
2.2只能分成满足CA,CP,AP三种情况
a) CA: 单点集群.满足一致性和可用性,分区容忍性不强.
b) CP: 满足一致性,分区容忍性,但可用性不高.
c) AP: 满足可用性,分区容忍性,但一致性较差.
六. BASE思想
1. 关系数据库的ACID模型
a) Atomicity原子性:一个事务中所有操作都必须全部完成,要么全部不完成。
b) Consistency一致性. 在事务开始或结束时,数据库应该在一致状态。
c) Isolation隔离层. 事务将假定只有它自己在操作数据库,彼此不知晓。
d) Durability. 一旦事务完成,就不能返回。
总结: 高一致性 + 可用性 但是很难进行分区:
2. BASE模型反ACID模型
完全不同ACID模型,牺牲高一致性,获得可用性或可靠性:
a) Basically Available基本可用。支持分区失败(e.g. sharding碎片划分数据库)
b) Soft state软状态 状态可以有一段时间不同步,异步。
c) Eventually consistent最终一致,最终数据是一致的就可以了,而不是时时高一致。
七. 下载安装
1.下载地址:
英文官网: https://redis.io/
中文官网: http://www.redis.cn/
2.将下载好的tar.gz拷贝到Linux: /usr/local目录下
3.解压缩并且进入目录/usr/local/redis-xxx
4.安装gcc-c++
yum install gcc-c++
5.执行安装命令
make&&make install
八. 初始配置
1.配置文件位置
/usr/local/redis-xxx/redis.conf
2.备份配置文件
/redis-conf-copy/redis.conf
3.修改为后台运行
将备份的配置文件中daemonize no修改为yes
4.进入命令目录并启动服务以及找到配置文件位置
cd /usr/local/bin/
redis-server /redis-conf-copy/redis.conf
5.打开新的命令终端查看服务是否启动
ps -ef|grep redis
redis默认端口6379
6.进入redis
redis-cli -p 6379
7.测试redis是否正常
输入ping,会收到回复pong
8.测试Key-Value保存
set key value
get key
9.测试读写速度
执行benchmark
9.停止服务
SHUTDOWN
Exit
九. 内存数据库
1.Redis有多少个数据库?
redis默认存在16个库,每个库拥有自己唯一的下标,类似于数组从0开始,默认使用0号库.
2.如何切换Redis数据库
select 下标
3.获得当前数据库中key数量
dbsize
测试插入后的数据库key数量
set k1 v1
set k2 v2
set k3 v3
4.获得所有的key内容
keys *
5.占位符?
keys i?
获得以i开头所有的key
keys ?1
获得以1结尾所有的key
6.清除本数据库所有的key
flushdb
7.清除16个库中所有的key
flushall
Redis命令大全: redisdoc.com
十. key关键字
1. exists
判断是否存在某个key
存在返回1,不存在返回0.
2. move
移动到其他的库
3. ttl
Time to live 过期时间
返回过期时间还有多少秒,返回-1 永不过期, 返回-2 已经过期.
设置过期时间: expire key second
4. type
获得Key的类型
十一. 五大数据类型
Redis的数据类型相较于其他NoSQL实现更加多元化,虽然同样属于KV类型非关系型数据库,但是value的类型有以下五种:
String: 字符串,用于网页标题,点赞数量等等...
List: 有序列表
Set: 散列集合
Zset: 有序集合
Hash: Redis对象
1. String(字符串)
最基本的数据类型,二进制安全,在redis中一个string类型的value最大可以是512m.
二进制安全指的,可以保存二进制文件数据,也可以保存对象序列化信息.
set/get/del/append/strlen
1) del
删除key
2) append
找到key并在value后追加
3) strlen
获得字符串的长度
4) incr
自增,要求数字
5) decr
自减
6) incrby
指定增量自增
语法: incrby key 增量
7) decrby
指定减量自减
语法: incrby key 减量
8) getrange
获得范围内数据(substring)
语法: getrange key beginIndex endIndex
9) setrange
从指定位置开始替换,替换相同数量的内容(replace)
语法: setrange key beginIndex content
10) setex
设置kv同时指定存活时间
语法: setex key time value
11) setnx
当key不存在时就设置值
语法: setnx key value
12) mset
批量设置kv
13) mget
批量通过key获得value
14) msetnx
都不存在时批量设置
2. List(列表)
简单的字符串列表,按照插入顺序进行排序,可以添加元素到头部或者尾部.
lpush/rpush/lrange/lpop/rpop/lindex/irem/ltrim/rpoplpush/lset/linsert
1) lpush
从集合左侧推入数据
2) rpush
从集合右侧推入数据
3) lrange
获得集合数据
4) lpop
左出栈
5) rpop
右出栈
6) lindex
按照下标获得元素
7) lrem
删除指定个数的指定值
语法: irem count value
8) ltrim
将列表中的元素截取一部分,重新赋值给key
9) rpoplpush
语法: rpoplpush list1 list2
集合1右出数据,集合2左入数据
10) lset
语法: lset list index value
插入值到指定下标
11) linsert
在指定值 前/后 插入指定值
语法: linsert list before/after target value
总结: 列表可以对于左右操作十分方便快速,中间数据操作效率低下.
3. Set(集合)
字符串类型的无序集合,散列.
sadd/smembers/sismembers/scard/srem/srandmember/spop/smove/sdiff/sinter/sunion
1) sadd
将数据插入集合中
语法: sadd key value[]
2) smembers
获得集合中的数据
语法: smembers key
3) sismembers
查询集合中是否存在数据
语法: sismembers
4) scard
获得集合中元素个数
5) srem
移除指定元素
6) srandmember
随机抽取几个数字
7) spop
随机出栈
8) smove
从一个集合移动数据到另一个集合
语法: smove set1 set2 value
9) sdiff
差集
10) sinter
交集
11) sunion
并集
4. Hash(哈希,类似于java中的java.util.Map)
Hash是一个键值对集合,是一个field和value的映射表,hash特别适合保存对象.
类似于java中的: Map<String,Object>
仍然是KV模式,但是V是一个键值对
hset/hget/hmset/hgetall/hdel/hlen/hexists/hkeys/hvals/hincrby/hincrbyflout/hsetnx
1) hset
2) hget
3) hmset
4) hmget
5) hgetall
6) hdel
7) hlen
8) hexists
9) hkeys
10) hvals
11) hincrby
12) hincrbyflout
13) hsetnx
5. Zset(sorted set: 有序集合)
有序集合,每个值关联一个double类型的分数.
之前的set是k1 v1 v2
现在的zset是 k1 score1 v1 score2 v2
zadd/zrange/zrangebyscore/zrem/zcard/zcount/zrank/zscore/zrevrank/
zrevrange/zrevrangebyscore
1) zadd
2) zrange
withscores
3) zrangebyscore
(
limit
4) zrem
5) zcard
6) zcount
7) zrank
8) zscore
9) zrevrank
10) zrevrange
11) zrevrangebyscore
(
limit
十二. 配置文件
1) units单位
2) include包含
3) general通用
daemonize: yes/no
守护进程,作用允许redis在关闭命令终端时继续在后台工作.
databases: integer
设置redis启动时创建内存数据库的数量.
pidfile:
线程管道文件
port: 6379
端口设置
tcp-backlog: 511
连接队列
backlog队列总和 = 未完成三次握手队列 + 已经完成三次握手队列.
bind: 127.0.0.1
绑定服务器
timeout: 0
对于客户端连接到redis时,可以采用超时关闭连接模式以节约内存,默认连接超时时间0,表示永不关闭.
开发中建议设置为0,生产中建议配置为300即5分钟后断开
tcp-keepalive
Redis集群心跳检测,每隔一段时间发送心跳检测,获得集群中其他redis是否依然在运行.
loglevel: notice
日志等级: 默认 notice(通知),开发时允许调成debug
logfile: “”
日志文件位置
建议设置logfile stdout系统输出设备
syslog-enabled: no
系统日志开关
sylog-ident: redis
系统日志开头文字(标识)
4) snapshotting快照
5) replication复制
6) security安全
config get requirepass: 获得必须的密码
config get dir: 获得当前打开命令终端的路径
一部分日志会保存到当前打开终端的路径下.
config set requirepass: 设置必须的密码
设置完密码后redis需要必须的密码验证才可以使用.
如果希望解除密码验证,只需要将必须密码设置为””即可.
auth your-password
7) limits限制
Maxclients: 10000
最大连接客户端
Maxmemory:
最大内存
Maxmemory-policy: noeviction
过期策略算法:
Lru:最近最少使用
Random: 随机
Ttl: 有限时间内
单词解释:
Volatile: 保护
Allkeys: 非保护
缓存过期策略:
Noeviction(默认): 不进行移除,永不过期
Volatile-lru: 使用LRU算法移除key,只作用于设置了过期时间的key
Allkeys-lru: 使用LRU算法移除key
Volatile-random: 随机移除, 只作用于设置了过期时间的key
Allkeys-random: 随机移除
Volatile-ttl: 移除那些ttl值小的key,即那些最近要过期的key.
Maxmemory-samples: 5
由于LRU与TTL算法都非精确算法,可能存在误差,可以使用测试计算误差.
设置样本数量,默认5个.
减少测试样本数量会降低测试准确度.
增加测试样本数量会增加测试时间.
8) append only mode追加
十三. 持久化
1.RDB
1.1 什么是RDB?
RDB是Redis Database的简称.
1.2 RDB有什么用?
在指定的时间间隔内,将内存中的数据集快照写入磁盘.
Snapshot快照,它恢复时时将快照文件直接读到内存里.
1.3 RDB的原理
Redis会单独创建(fork)一个子进程来进行持久化,会将数据写入到一个临时文件中,带持久化过程都结束了,再用这个临时文件替换上次持久化好的文件.整个过程中,主进程是不进行任何IO操作的,这就确保了主进程极高的性能.如果需要对大规模的数据进行恢复,且对数据的完整性不是非常敏感,那么RDB方式要比AOF方式更加高效.RDB方式的缺点是最后一次持久化之后的数据可能丢失.
1.4 什么是fork?
复制一个与当前进程一样的进程.新进程的所有数据(变量,环境变量,程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为进程的子进程.子进程将内存中的数据通过IO保存到硬盘中进行持久化,保存的文件名为dump.rdb.
1.5 如何使用RDB持久化?
1.5.1打开配置文件redis.cnf
1.5.2找到SNAPSHOTTING
1.5.3持久化备份机制
save <second> <change>
保存 秒 变更次数
以上设置为在多长时间内发生变更次数达到多少就进行保存.
默认值:
save 900 1 15分钟内有一次
save 300 10 5分钟10次
save 60 10000 1分钟内达到1万次
以上内容也可以进行自定义设置
1.5.4禁用RDB
save “”
禁用后Redis就不能进行RDB持久化,请慎用此设置.
1.5.5数据恢复
将dump.rdb文件放置在启动位置即可自动恢复.
1.5.6立即备份
在Redis命令行输入save可以立即备份
1.5.7遇到后台持久化错误时是否可以继续写操作
stop-writes-on-bgsave-error yes
有数据运维或RedisDBA可以允许关闭,否则会影响数据一致性.
1.5.8是否压缩持久化文件
rdbcompression yes
压缩节约硬盘空间,压缩式需要浪费CPU,不压缩反之.
1.5.9压缩验证算法
rdbchecksum yes
对备份数据进行验证,需要提示Redis10%的性能消耗.
1.5.10备份文件名及路径
dbfilename dump.rdb
dir ./ --当前路径
1.5.11总结
一. 以下三种方式可以 产生/更新 持久化备份文件.
- fork进程触发
- save命令
- flushall
shutdown也可以进行持久化备份,生产中一般不会经常运行此命令.
二. 如何恢复?
将文件copy到启动目录就可以进行恢复,生产中一般放置到启动目录下.
三. 优势与劣势分析
优势: 适合大规模的数据恢复
劣势: 数据的一致性不高,在fork进程启动时内存2倍膨胀.
2.AOF
2.1什么是AOF?
AOF是Append Only File的简称.
AOF与RDB协作运行,不产生冲突.
2.2为什么需要AOF?
弥补RDB的劣势.
2.3AOF的原理
以日志的形式来记录每个写操作,将redis执行过的所有指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复.
使用异步方式进行记录
2.4 如何使用AOF?
复制并且重命名aof文件.
2.4.1默认关闭AOF
appendonly no
手动设置为yes
2.4.2默认文件名称
appendfilename "appendonly.aof"
2.4.3开启服务进入Redis立即产生appendonly.aof文件
2.4.4设置kv到redis
2.4.5清空所有数据库并且退出redis
2.4.6查看appendonly.aof文件内容
2.4.7移除rdb文件确保不会进行RDB恢复
2.4.8删除FLUSHALL指令
生产环境中一般是不允许手动修改appendony.aof的.
2.4.9启动并且进入Redis,查看key
2.4.10启动是读取备份文件的优先级
Redis启动时首先会去读取aof文件,没有aof再去读取rdb文件.
可以将adf文件故意加入错误内容,在同时有rdb和aof文件的Redis启动进行测试,如果报错说明优先读取aof,不报错说明优先读取rdb文件.
备份被写坏的aof文件,再使用redis-check-aof –fix appendonly.aof命令,可以智能检测aof文件的错误并且修改.
2.4.11同步文件策略
# appendfsync always: 同步持久化
每次发生数据改变立即记录到磁盘,性能较差但完整性最好.
appendfsync everysec: 每秒记录(默认设置)
性能较好,但是如果在宕机的1秒内保存的数据,有可能丢失.
# appendfsync no: 不持久化
2.4.12为什么需要重写?
AOF采用追加的方式,当AOF文件越来越大时,需要对文件进行精简压缩.当文件大小超过所设定的阈值时,Redis就会启动AOF文件内容压缩.将重复的相同的操作指令,进行优化,使文件内容缩小,但是运行结果相同.也可以使用指令bgrewriteaof.
2.4.13重写的机制
AOF持续增长到一定大小时,会fork出一条新的进程来将文件重写(先产生临时文件,最后再rename).遍历新进程的内存中数据,每条记录有一条的Set语句.重写AOF文件并没有读取旧的AOF文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的AOF文件,这点和快照有所类似.
Redis会记录上次重写时的AOF大小,默认是当AOF文件大小时上次rewrite后大小的一倍并且文件大小超过64m时触发.
no-appendfsync-on-rewrite no
重写时可以允许appendfsync,默认no,保证数据安全性
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
设置重写的基准值
2.4.14总结
优势: 保存数据一致性非常高
劣势:
备份时采用每秒追加,或者同步追加功耗巨大
相同数据aof文件要远远大于rdb文件,并且恢复速度要慢恢复时间要久.
十四. 事务
1. 什么是redis的事务?
可以一次性执行多个命令,本质上是一组命令的集合.一个事务中的所有命令都会序列化,会按照顺序的执行而不会被其他命令插入,不允许加塞.(类似于批处理)
2. redis如何保证一致性
如果多个redis命令操作需要保证一致性,那么就需要开启redis事务.
3. redis的事务能做什么?
一个队列中,一次性,顺序性,排他性的执行一系列的命令.
4. 如何使用redis事务?
4.1事务常用命令
4.1.1multi
标记一个事务块的开始
4.1.2exec
执行所有事务块内的命令
4.1.3discard
取消,放弃执行事务块内的所有命令
4.1.4watch key [key]
监视一个或多个key,如果在事务执行前被监视的key被其他人操作发生改动,那么事务将被打断.(类似于Git提交冲突)
4.1.5unwatch
取消watch命令对所有key的监视
4.2事务操作中的一些情况
关键字: QUEUED 队列
(redis事务操作中指操作入队)
4.2.1Case1: 正常执行
4.2.2Case2: 放弃事务
4.2.3Case3: 一票否决(没有成功添加队列)
4.2.4Case4: 待定审核(添加队列成功但执行错误)
4.2.5Case5: watch监控
乐观锁:
不进行锁定,只在出现问题是进行类似于版本控制器的冲突解决.
提交版本必须大于当前版本才能执行.
悲观锁:
锁定数据,不允许其他线程修改,能很好的保证数据一致性,但会影响并发性能.
如: 行锁 表锁 读锁 写锁
watch案例:信用卡余额与应还金额.
1.正常的操作
2.多线程冲突操作
线程一监听money
线程二修改money
线程一开启事务,并且修改money,执行事务时会出现失败提示返回nil空
3.解决多线程冲突操作
线程一监听money
线程二修改money,此时线程二应该通知线程一
线程一开启事务前关闭监听等待线程二修改完成再次加入监听,并且修改money,执行事务
4.3总结:
1.一旦执行exec那么之前的watch都会被清空
2.不保证原子性,redis命令集中一条执行失败,其余的也能执行成功.
3.没有回滚机制
十五. 主从复制
replication
十六. Jedis
redis 远程连接方法
解决方法
1、修改redis服务器的配置文件
vi redis.conf
注释以下绑定的主机地址
# bind 127.0.0.1
vim redis.conf
bind 0.0.0.0
protected-mode no
2、修改redis服务器的参数配置
修改redis的守护进程为no,不启用
127.0.0.1:6379> config set daemonize "no"
OK
修改redis的保护模式为no,不启用
127.0.0.1:6379> config set protected-mode"no"
OK
或者
config set requirepass 123 ->123是密码
注意:开启 6379端口
3、远程连接
$ redis-cli -h 138.138.138.138 -p 6379
redis>ping
PONG
1.如何使用Jedis?
在springboot工程中添加jedis的依赖
2.常用命令
2.1测试
ping()
2.2设置string值
set(String key,String value);
2.3根据key获得值
get(String name);
2.4获得所有的key
getkeys(“pattern”)
3.事务
Jedis j = new Jedis(“ip”,port);
Transactional tran = j.multi();
4.存取对象
4.1使用hash方式保存
4.2使用字节方式保存
IDEA如何将对象产生序列化ID
将自动产生序列化ID勾选,在类名上使用ALT+回车即可产生序列化ID