1、入门
- 是完全开源免费的,用c语言编写的,遵守BSD协议,是一个高性能的(key/value)分布式内存数据库,基于内存运行并支持持久化的NoSql数据库,是当前最热门的NoSql数据库之一,也被人们称为数据结构服务器。
- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用
- Redis不仅仅支持简单的key/value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
- Redis支持数据的备份,即master-slave模式的数据备份
- 内存存储和持久化:Redis支持异步将内存中的数据写道硬盘上,同时不影响继续服务取最新N个数据的操作。如:可以将最新的10条评论的ID放在Redis的List集合里面。
- 模拟类似于HttpSession这种需要设定过期时间的功能
- 发布,订阅消息系统
- 定时器,计数器
- linux下的下载和安装
- http://download.redis.io/releases/redis-3.2.8.tar.gz来下载Redis的安装包
- tar -zxvf 文件名字来解压压缩包
- 进入到解压以后的目录中,并执行make命令(如果没有安装gcc则会报错)
- 使用yum install gcc-c++来安装gcc
- 使用make依然报错,,是因为原来的残余文件还在
- 使用make distclean来清除原来的残余文件
- 再次使用make来安装,并且使用make install来检验是否安装完成
- 使用cp redis.conf /soft/ 将redis的出厂设置备份到了soft文件夹下
- 可以使用redis-benchmark来测试运行速度,仅限启动了redis服务的状态下
2、杂项
- 默认使用16个库,下标从0开始
- 其中的数据不共通
- 使用dbsize,来查看当前数据库中的key数量
- 使用keys *来查看所有的key,或者keys k?来模糊查询,?为占位符
- flushdb,清除库。flushall,清除所有库。
3、Redis的数据类型
- String(字符串)
- String是Redis的基本数据类型,与Memcached一摸一样的模型,一个key对应一个value。
- String类型是二进制安全的,意思是Redis的string可以包含任何数据。比如jpg图片或者序列化的对象。
- String类型是Redis最基本的数据类型,一个Redis中文字符串value最多可以是512M。
- Hash(哈希,类似java里的map)
- 是一个键值对集合
- 是一个String类型的field和value的映射表,hash特别适合用于存储对象
- 类似java里面的Map<String,Object>
- List(列表)
Redis列表是个简单的字符串列表,按照插入顺序排序,你可以添加一个元素导列表的头部(左边)或者尾部(右边)。他的底层实际是个链表。 - Set(集合)
是String类型的无序集合。它是通过HashTable实现的。 - Zset(sorted set:有序集合)
- zset和set一样,都是String类型的元素集合,且不允许重复的成员。
- 不同的是每个元素都会关联一个double类型的分数。
- redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数却可以重复。
- http://redisdoc.com/命令集
- key
命令 | 效果 |
keys * | 查看所有的键 |
exists 键名 | 判断键是否存在 |
move 键名 下标 | 将当前库的key挪到目标库 |
expire 键名 秒数 | 设置过期时间 |
ttl 键名 | 检查还剩多少时间过期 |
type 键名 | 检查该键的类型 |
set 键名 值 | 创建该键名或者覆盖该键名 |
get 键名 | 获取该键名 |
del 键名 | 删除键 |
- String
命令行 | 结果 |
append 键名 值 | 和set效果一样 |
strlen 键名 | 获取键值的长度 |
append 键名 内容 | 将内容追加到键上去 |
incr/decr 键名 | 将int型数据加一或减一 |
incrby/decrby 键名 数值 | 加上数值或者减去数值 |
setrange k1 起始下标 内容 | 将内容覆盖到以下标开始的部分去 |
getrange k1 起使下标 结束下标 | 截取字符串 |
setex 键名 时间长短 值(set with expire) | 创建键的时候就设置存活时间 |
setnx 键名 值(set if not exists) | 如果不存在则设置 |
mset k1 v1 k2 v2 k3 v3 | 一次性设置多个键值对 |
mget k1 k2 k3 | 获得多个键值对 |
msetnx k1 v1 k2 v2 k3 v3 | 设置多个键值对,但必须满足都不存在的条件 |
- List
命令 | 效果 |
lpush/rpush 列表名字 v1 v2 v3 | 载入一个list |
lrange 列表名字 起始下标 终止下标(和lpush相反,rpush一致) | 获取list的一截 |
lindex 列表名字 下标索引 | 显示该下标的数字 |
llen 列表名字 | 获取长度 |
lrem 列表名字 几个 value | 删除掉几个这种value |
ltrim 列表名字 起始下标 终止下标 | 截取其中一串重新赋值给自己 |
rpoplpush 源列表 目标列表 | 将原来的右出栈,目标左入栈 |
lset 列表名字 下标 值 | 将列表中某一个下标的值改为目标值 |
linsert 列表名字 before/after 值 插入值 | 在值前/后插入一个值 |
- 他是一个字符串链表,left,right都可以插入添加
- 如果键不存在,创建新的链表
- 如果键已经存在,新增内容
- 如果值全部移除,对应的键也就消失了
- 链表的操作无论是头和尾效率都很高,但假如是对中间元素进行操作,效率就很低
- Set
命令 | 效果 |
sadd 集合名字 v1 v2 v3 | 保存不重复的部分到集合中去 |
smembers 集合名字 | 显示所有的内容 |
sismember 集合名字 value | 判断该值是否已经存在 |
scard 集合名字 | 获取元素个数 |
srem 集合名字 value | 删除value |
srandmember 集合名字 个数 | 随机显示几个value |
spop 集合名字 个数 | 随机出栈几个数字 |
smove 源集合 目标集合 值 | 将值从源集合中移动到目标中 |
sdiff 母集合 子集合 子集合 | 在第一个set中,且不在后面任意一个set中 |
sinter 母集合 子集合 子集合 | 求交集 |
sunion 母集合 子集合 子集合 | 求并集 |
- Hash(KV模式不变,但V是一个键值对)
命令 | 效果 |
hset key key1 value1 | 创建了一个<String,Object> |
hmset key key1 value1 key2 value2 | 注入多个属性 |
hmget key key1 key2 key3 | 显示多个属性 |
hgetall key | 显示key之下的所有的key value |
hdel key key1 | 删除key里面的某个key |
hlen key | 显示有几个键值对 |
hexists key key1 | 判断键值对中是否包含该键名 |
hkeys/hvals key | 显示所有的键名或者键值 |
hincrby/hincrbyfloat key key1 value1 | 目标的键值对的值加上多少 |
hsetnx | 判断该键值对是否存在,不存在则添加 |
- Zset
命令 | 效果 |
zadd zset01 score1 value1 score2 value2 | 增加一个新的zset,其中和set一样,一个key下面跟着键值对,但是子级的的键名就是一个数字作为分数 |
zrevrange/zrange zset01 0 -1 withscores | 显示所有的zset,加上withscores则会带上分数 |
zrevrangebysocre/zrangebyscore zset01 min max | 显示范围内的键值对,值前面加上(代表不包含,末尾可追加limit x y,和sql用法一致 |
zrem zset01 value | 删除value为这个值的键值对 |
zcard zset01 | 显示有几个键值对 |
zcount zset01 60 80 | 显示60到80分的键值对有几个 |
zrevrank/zrank zset01 value4 | 代表给value4排序,排第几位 |
zscore zset01 value4 | 获取value4的分数 |
4、配置文件
配置项 | 效果 |
include | 用来包含其他的配置文件,当前文件作为总阀 |
config get *** | 获取配置文件中*** |
config set requirepass *** | 设置*** |
auth 密码 | 输入密码,否则无法操作 |
Maxmemory-policy | 缓存过期策略 |
Maxmemory-samples | 设置样本数据,LRU算法和最小TTL算法都并非是精确的算法,而是估算值,所以你可以设置样本的大小。redis默认会检查多个key并选择其中LRU的那个 |
timeout | 闲置多长时间以后会关闭连接 |
loglevel | 日志记录级别 |
logfile | 日志记录方式 |
dir ./ | 本地数据库存放目录 |
maxclients | 同一时间最大客户端连接数 |
maxmemory | 最大内存限制 |
Stop-writes-on-bgsave-error | 配置为no,表示不在乎数据不一致或者有其他的 |
rdbcompression | 对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算法进行压缩。如果不想消耗CPU,设置为关闭。 |
rdbchecksum | 在存储快照后,还可以让redis使用CRC64算法来进行数据校验,但是这样子也会增加大约10%的性能消耗,如果希望取到最大的性能提升,可以关闭此功能。 |
appendfsync | 追加策略,一般使用everysec |
no-appendfsync-on-rewrite | 重写时是否可以运用appendfsync,用默认no即可,保证数据安全性 |
Maxmemory-policy:
- volatile-lru:使用LRU算法移除key,只对设置了过期时间的键
- allkeys-lru:使用LRU算法移除key
- volatile-random:在过期集合中移除随机的key,只对设置了过期时间的键
- allkeys-random:移除随机的key
- volatile-ttl:移除那些ttl值最小的key,即那些即将过去的key
- noeviction:不进行移除,针对写操作,只返回错误信息
5、持久化
1、RDB
定义:在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,他恢复时是将快照文件直接读到内存里
Redis会单独创建(fork)一个子进程来进行持久化,会将数据写入到一个临时文件中,等持久化的过程结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能。如果需要大规模数据的回复,且对于数据恢复的完整性不是非常敏感,那么RDB方式要比AOF更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。,fork时占用2倍的性能。
当执行了flushall或者flushdb的操作时,会直接生成当前操作对应的dump.rdb文件,不管是否达到了频率。而shutdown的时候一样会产生一个dump.rdb,用来记录。另外save操作一样会直接生成dump.rdb。
redis-cli config set save ""停止RDB保存规则的方法。
redis-check-rdb --fix dump.rdb修复rdb文件
2、AOF
定义:以日志形式,记录每个写操作,将redis执行过的所有指令记录下来(读操作无需记录)包含了flushall,只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的时候就会根据日志文件的内容将指令从前到后执行一次以完成数据的恢复工作。
rdb文件和aof文件可以共存,并且先调用aof文件。
当aof文件报错以后,可以使用redis-check-aof --fix appendonly.aof来修复
为了避免文件越来越大,,新增了重写机制,当AOF文件的大小超过了所设定的阙值的时候,redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集,可以使用命令bgrewriteaof。
6、事务
定义:可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行,而不会被其他命令插入。
能在一个队列中,一次性、顺序性、排他性的执行一系列命令。
常用命令
命令 | 效果 |
DISCARD | 取消事务,放弃执行事务块内的所有命令 |
EXEC | 执行所有事物块内的命令 |
MULTI | 标记一个事务块的开始 |
UNWATCH | 取消WATCH命令对所有key的监视 |
WATCH | 监视一个或多个key,如果在事务执行之前这些key被其他命令所改动,那么事务将会被打断 |
悲观锁,每次去拿数据的时候都会认为别人会修改数据,所以每次拿数据的时候都会上锁,这样别人想拿这个数据就会block直到他拿到锁。传统的关系型数据库里边就用到了很多这种锁,比如行锁,表索,读锁,写锁等。都是在做操作之前先上锁。
乐观锁,每次去拿数据的时候,都会认为别人不做修改,所以不上锁。但是在更新的时候会判断在此期间是否有人更新过数据,可以使用版本号机制。即每次操作的时候重新读取版本号,查看此期间是否有人修改过数据。乐观锁适用于多读的应用类型,可以提高吞吐量。乐观锁策略:提交版本必须大于记录当前版本才能执行更新。
redis的事务特性:
- 单独的隔离操作:事务中的所有命令都会序列化、按顺序的执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
- 也没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在“事务内的查询要看到事务里的更新,在事务外查询不能看到”这个让人万分头痛的问题。
- 不保证原子性:redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚。
7、消息的发布和订阅
进程间的消息通信模式:发送者发布信息,订阅者接受信息
8、主从复制
Master以写为主,Slave以读为主
master主机6379
slave从机80、81,从机没有资格修改主机设置的值
主机死了,从机原地待命,主机回来继续工作
从机死了,回来需要重新连接主机,否则只会有以前的文件,而不会继续备份,并且身份变回了master
配置文件中要修改的有daemonize、pidfile、port、logfile、dbfilename
一主二仆
命令 | 效果 |
info replication | 显示信息 |
slaveof 127.0.0.1 6379 | 在从机上输入命令,确定谁是主机 |
slaveof no one | 当主机死掉以后使用,将自己变成主机,主机回来也无效了,变成了不相干的两组 |
薪火相传:当从机有了自己的从机以后,同样会把数据给复制过去,同时这都算从机,主机只有一台
- slave启动成功连接到master后会发送一个sync(同步)命令
- Master接到命令启动后台的存盘进程,同时收集所有接收到用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,以完成一次完全同步。
- 全量复制:而slave服务在接收到数据库文件数据后,将其存盘加载到内存中。
- 增量复制:master继续将新的所有收集到的修改命令依次传给slave,完成同步
- 但是只要是重新连接master,一次完全同步(全量复制)将被自动执行
哨兵模式:反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库
- 目录下新建sentinel.conf文件,名字规范
- sentinel monitor host6379 127.0.0.1 6379 1,当主机6379死了以后,代表slave投票,谁票数多,谁就是新的主人
- redis-sentinel /soft/sentinel.conf开启这项服务,和检查aof写法类似
- 当主机回来以后,会自动变为slave端
9、连接redis
- 修改redis.conf
- 注释掉bind 127.0.0.1
- 将protected-mode yes修改为protected-mode no
- 将daemonize yes修改为daemonize no
- 此时如果连接还是出错,可以尝试修改iptable,在centos的命令行中按顺序执行以下代码
systemctl stop firewalld.service
systemctl disable firewalld.service # 前两行关闭防火墙
iptables -I INPUT 1 -p tcp -m state --state NEW -m tcp --dport 6379 -j ACCEPT
service iptables save # 如果报错则运行第五行代码来安装,否则可以跳过第五行
yum install iptables-services
systemctl enable iptables.service
10、连接jedis
使用的jar有jedis-3.1.0.jar、commons-pool2-2.4.2.jar
Jedis jedis=new Jedis("虚拟机地址","端口号");//可以通过jedis,来操作redis的api
-m state --state NEW -m tcp --dport 6379 -j ACCEPT
service iptables save # 如果报错则运行第五行代码来安装,否则可以跳过第五行
yum install iptables-services
systemctl enable iptables.service
## 10、连接jedis
使用的jar有jedis-3.1.0.jar、commons-pool2-2.4.2.jar
```java
Jedis jedis=new Jedis("虚拟机地址","端口号");//可以通过jedis,来操作redis的api