为什么使用nosql(not only sql)
- 单机mysql时期
- jsp到dao到数据库
- Memcached(缓存)+Mysql+垂直拆分
- jsp到dao到Memcached到多个数据库实例
- Mysql的主从读写分离
- jsp到dao到Memcached
- Memcached到主数据库负责写(增删改)数据,从库在主库写完之后立刻更新数据;
- Memcached到从数据库负责读(查)数据;
- jsp到dao到Memcached
- 分库分表+水平拆分+mysql集群
- jsp到dao到Memcached到一个个集群,集群中对应读写分离
- Mysql的扩展性瓶颈
- 如果需要存储很大空间的文件,Mysql扩展性差,大数据io差,表结构更改困难;
- 现状
安装
- 下载redis压缩包
- 使用wget命令后接资源地址下载压缩包
- wget http://download.redis.io/releases/redis-4.0.8.tar.gz
- 也可以使用vmware的共享目录在windows上面下载然后放进linux中
- 将压缩包放进/opt目录
1.使用tar -zxvf redis-3.0.4.tar.gz解压
2.然后在解压目录中使用make命令
3.如果make命令报缺少gcc则使用yum命令安装 yum install gcc-c++
4.make install
启动redis
- 备份redis.conf文件到/myredis文件夹中,然后将备份的redis.conf(下面的都是用的备份)中的daemonize no改成yes;
- 然后在/usr/local/bin下面使用redis-server /myredis/redis.conf启动服务器,然后redis-cli -p 6379启动客户端,然后ping执行连通性测试,正确输出pong,那么就正常启动了;
- 退出输出shutdown然后exit即可;
几个常用命令
- redis有16个库,可以使用select 数字来选择库
- 使用dbsize可以查看当前库中有多少个键值对
- 使用flushdb可以清空当前库
- 使用flushall可以清空所有库
redis数据类型
每种类型对应的底层结构:https://www.cnblogs.com/charlas/p/7606077.html
- 字符对象:int,raw,embstr
- 列表对象:ziplist,skiplist
- hash对象:ziplist,hashtable
- set对象:intset,hashtable
- zset:ziplist,skiplist
key(键)
使用
- keys *:查询当前库的所有key
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
3) "k1"
- exists key:判断key是否存在,存在返回1,不存在返回0;
127.0.0.1:6379> EXISTS k1
(integer) 1
127.0.0.1:6379> EXISTS k11
(integer) 0
- move key db:将key从当前库移动到db库;
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
3) "k1"
127.0.0.1:6379> move k1 1
(integer) 1
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> keys *
1) "k1"
127.0.0.1:6379[1]>
- expire key time:将key设置成time(秒)过期
- ttl key:查看key的生命周期,-1表示永不过期,-2表示已过期(移除该元素),一般配合expire命令使用
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
3) "k1"
127.0.0.1:6379> ttl k1
(integer) -1
127.0.0.1:6379> expire k1 10
(integer) 1
127.0.0.1:6379> ttl k1
(integer) 8
127.0.0.1:6379> ttl k1
(integer) 6
127.0.0.1:6379> ttl k1
(integer) 5
127.0.0.1:6379> ttl k1
(integer) 4
127.0.0.1:6379> ttl k1
(integer) 4
127.0.0.1:6379> ttl k1
(integer) 3
127.0.0.1:6379> ttl k1
(integer) 2
127.0.0.1:6379> ttl k1
(integer) 1
127.0.0.1:6379> ttl k1
(integer) 1
127.0.0.1:6379> ttl k1
(integer) -2
127.0.0.1:6379> get k1
(nil)
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
127.0.0.1:6379>
- type key :查看key是什么类型
127.0.0.1:6379> type k2
string
127.0.0.1:6379> LPUSH mylist 1 2 3 4 5
(integer) 5
127.0.0.1:6379> LRANGE mylist 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
127.0.0.1:6379> type mylist
list
127.0.0.1:6379>
- del key:表示删掉key
127.0.0.1:6379> del mylist
(integer) 1
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
127.0.0.1:6379>
- persist key:移除key的有效时间,key将保持永久
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
127.0.0.1:6379> expire k2 60
(integer) 1
127.0.0.1:6379> ttl k2
(integer) 56
127.0.0.1:6379> PERSIST k2
(integer) 1
127.0.0.1:6379> ttl k2
(integer) -1
127.0.0.1:6379>
- randomkey :从已有的所有key中随机返回一个key
1) "k2"
2) "k3"
127.0.0.1:6379> RANDOMKEY
"k2"
127.0.0.1:6379>
- rename key newkey:修改key的名称为newkey
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
127.0.0.1:6379> RENAME k2 k1
OK
127.0.0.1:6379> keys *
1) "k1"
2) "k3"
127.0.0.1:6379>
String(字符串)
- String是redis最基本的类型,可以理解成跟Memcached一模一样的类型,一个key对应一个value
- string类型是二进制安全的,意思是redis的string可以包含任何数据,比如jpg图片或者序列化对象;
- string类型是redis的最基本的数据类型,一个redis中字符串value最多可以是512M
使用
- set key value:设置key的值为value
127.0.0.1:6379> keys *
1) "k1"
2) "k3"
127.0.0.1:6379> set k2 v2
OK
- get key:获取key的值
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
3) "k3"
127.0.0.1:6379> get k1
"v1"
- del key :表示删除key
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
3) "k3"
127.0.0.1:6379> del k1
(integer) 1
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
- append key newvalue:表示在key的原value值拼接加上newvalue
- strlen key :表示key的长度
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379> STRLEN k2
(integer) 2
127.0.0.1:6379> APPEND k2 12345
(integer) 7
127.0.0.1:6379> strlen k2
(integer) 7
127.0.0.1:6379> get k2
"v212345"
- incr key :将key值加一(key只能是数字,以下三种命令相同)
- decr key:将key值减一
- incrby key num:将key的值加num
- decrby key num:将key的值减num
127.0.0.1:6379> get k2
"1"
127.0.0.1:6379> INCR k2
(integer) 2
127.0.0.1:6379> get k2
"2"
127.0.0.1:6379> DECR k2
(integer) 1
127.0.0.1:6379> get k2
"1"
127.0.0.1:6379> INCRBY k2 3
(integer) 4
127.0.0.1:6379> get k2
"4"
127.0.0.1:6379> DECRBY k2 3
(integer) 1
127.0.0.1:6379> get k2
"1"
- getrange key n m:获取key从下标n到m(不包含)的子字符串
127.0.0.1:6379> get k2
"v212345"
127.0.0.1:6379> GETRANGE k2 0 -1
"v212345"
127.0.0.1:6379> GETRANGE k2 0 3
"v212"
- setrange key n newvalue :从key的第n(包含)位开始覆盖newvalue,若key不存在会新建key
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
127.0.0.1:6379> SETRANGE k1 0 XXX
(integer) 3
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
3) "k3"
127.0.0.1:6379> get k1
"XXX"
127.0.0.1:6379> get k2
"v212345"
127.0.0.1:6379> SETRANGE k2 0 XXX
(integer) 7
127.0.0.1:6379> get k2
"XXX2345"
- setex(set with expire) key time value:设置key值为value并设置过期时间time秒
127.0.0.1:6379> setex k3 10 v4
OK
127.0.0.1:6379> ttl k3
(integer) 8
127.0.0.1:6379> get k3
"v4"
127.0.0.1:6379> ttl k3
(integer) 1
127.0.0.1:6379> ttl k3
(integer) -2
127.0.0.1:6379> get k3
(nil)
- setnx(set if not exist) key value:设置key的值为value当key不存在时才设置,存在不覆盖
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
127.0.0.1:6379> get k1
"XXX"
127.0.0.1:6379> setnx k1 123123
(integer) 0
127.0.0.1:6379> get k1
"XXX"
127.0.0.1:6379> setnx k3 123123
(integer) 1
127.0.0.1:6379> get k3
"123123"
- mset key1 value1 key2 value2…:设置多个值(more)
- mget key1 key2 key3 …:获取多个值
- msetnx key1 value1…:设置多个值,当有任意一个key存在则所有的key都设置失败
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
3) "k3"
4) "k4"
127.0.0.1:6379> msetnx k4 v44 k5 v55
(integer) 0
127.0.0.1:6379> mget k4 k5
1) "v4"
2) (nil)
127.0.0.1:6379> msetnx k5 v55 k6 v66
(integer) 1
127.0.0.1:6379> mget k5 k6
1) "v55"
2) "v66"
Hash(哈希,类似java的Map)
- redis hash是一个键值对集合;
- redis hash是一个String类型的field和value的映射表,hash特别适合用于存储对象;
- 类似于java中的Map<String,Object>
使用
注意:KV模式不变,但V是一个键值对
- hset map k v:将map的值设置成kv键值对
127.0.0.1:6379> hset user id 11
(integer) 1
127.0.0.1:6379> hget user id
"11"
- hmset map k1 v1 k2 v2 k3 v3:一次性为map设置多个键值对
- hgetall map:一次性全部获取map的键值对
127.0.0.1:6379> hmset customer id 11 name li4 age 26
OK
127.0.0.1:6379> HGETALL customer
1) "id"
2) "11"
3) "name"
4) "li4"
5) "age"
6) "26"
- hdel map k:将map中的键为k的键值对删除,map中没元素的话则删除map
127.0.0.1:6379> hdel user id
(integer) 1
- hlen map:显示map拥有的键值对个数
127.0.0.1:6379> hgetall customer
1) "id"
2) "11"
3) "name"
4) "li4"
5) "age"
6) "26"
127.0.0.1:6379> HLEN customer
(integer) 3
- hexists map k:判断map中是否有键为k的键值对
127.0.0.1:6379> HEXISTS customer id
(integer) 1
127.0.0.1:6379> HEXISTS customer sex
(integer) 0
- hkeys map:取map的所有key值
- hvals map:取map的所有value值
127.0.0.1:6379> hkeys customer
1) "id"
2) "name"
3) "age"
127.0.0.1:6379> hvals customer
1) "11"
2) "li4"
3) "26"
- hincrby map k num:将map中k的值增加num
- hincrbyfloat map k floatnum:将map中的k值增加floatnum
127.0.0.1:6379> HINCRBY customer id 2
(integer) 13
127.0.0.1:6379>
127.0.0.1:6379> HINCRBY customer id 2
(integer) 15
127.0.0.1:6379> HINCRBYFLOAT customer id 2
"17"
127.0.0.1:6379> HINCRBYFLOAT customer id 0.1
"17.1"
127.0.0.1:6379> HINCRBY customer id 2.1
(error) ERR value is not an integer or out of range
- hsetnx map k v:当k不存在map中时才插入此键值对
127.0.0.1:6379> HSETNX customer age 25
(integer) 0
127.0.0.1:6379> hsetnx customer email abc@126.com
(integer) 1
List(列表)
- redis列表是简单字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部或者尾部,他的底层是一个链表;
使用
- lpush list value1 value2:往list中从左push数据,从左边先进去的数据排在最后
- rpush list value1 value2:往list中从右push数据,从右边先进去的数据排在最前
- lrange list n m:从左往右显示list中从n 到m的数据,
127.0.0.1:6379> lpush list01 1 2 3 4 5
(integer) 5
127.0.0.1:6379> LRANGE list01 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
127.0.0.1:6379> rpush list02 1 2 3 4 5
(integer) 5
127.0.0.1:6379> LRANGE list02 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
- lpop list:取list左边的元素;
- rpop list :取list右边的元素
127.0.0.1:6379> LRANGE list01 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
127.0.0.1:6379> lpop list01
"5"
127.0.0.1:6379> LRANGE list01 0 -1
1) "4"
2) "3"
3) "2"
4) "1"
127.0.0.1:6379> rpop list01
"1"
127.0.0.1:6379> LRANGE list01 0 -1
1) "4"
2) "3"
3) "2"
127.0.0.1:6379>
- lindex list num:获取list中下标为num的元素
127.0.0.1:6379> LRANGE list01 0 -1
1) "4"
2) "3"
3) "2"
127.0.0.1:6379> LINDEX list01 0
"4"
- llen list :获取list的长度
127.0.0.1:6379> LRANGE list01 0 -1
1) "4"
2) "3"
3) "2"
127.0.0.1:6379> LLEN list01
(integer) 3
- lrem list num value:删除list中num个value值,如果不够,则有多少个删多少个
127.0.0.1:6379> rpush list03 1 1 1 2 2 2 3 3 3 4 5 6
(integer) 12
127.0.0.1:6379> LRANGE list03 0 -1
1) "1"
2) "1"
3) "1"
4) "2"
5) "2"
6) "2"
7) "3"
8) "3"
9) "3"
10) "4"
11) "5"
12) "6"
127.0.0.1:6379> LREM list03 2 4
(integer) 1
127.0.0.1:6379> LRANGE list03 0 -1
1) "1"
2) "1"
3) "1"
4) "2"
5) "2"
6) "2"
7) "3"
8) "3"
9) "3"
10) "5"
11) "6"
127.0.0.1:6379> LREM list03 2 3
(integer) 2
127.0.0.1:6379> LRANGE list03 0 -1
1) "1"
2) "1"
3) "1"
4) "2"
5) "2"
6) "2"
7) "3"
8) "5"
9) "6"
- ltrim list n m:截取list的第n位(包含)到第m位(包含)并重新赋给list
127.0.0.1:6379> rpush list01 1 2 3 4 5 6 7 8
(integer) 8
127.0.0.1:6379> LRANGE list01
(error) ERR wrong number of arguments for 'lrange' command
127.0.0.1:6379> LRANGE list01 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "7"
8) "8"
127.0.0.1:6379> ltrim list01 3 5
OK
127.0.0.1:6379> LRANGE list01 0 -1
1) "4"
2) "5"
3) "6"
- rpoplpush list1 list2:将list1右边的元素pop出来然后push进list2的左边
127.0.0.1:6379> LRANGE list01 0 -1
1) "4"
2) "5"
3) "6"
127.0.0.1:6379> LRANGE list02 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> RPOPLPUSH list01 list02
"6"
127.0.0.1:6379> LRANGE list01 0 -1
1) "4"
2) "5"
127.0.0.1:6379> LRANGE list02 0 -1
1) "6"
2) "1"
3) "2"
4) "3"
5) "4"
6) "5"
- lset list index value:将list下标为index的元素替换成value
127.0.0.1:6379> LRANGE list01 0 -1
1) "4"
2) "5"
127.0.0.1:6379> lset list01 0 666
OK
127.0.0.1:6379> LRANGE list01 0 -1
1) "666"
2) "5"
- linsert list after/before value anothervalue:在list的元素value前或者后插入元素anothervalue
127.0.0.1:6379> LRANGE list01 0 -1
1) "666"
2) "5"
127.0.0.1:6379> LINSERT list01 before 666 999
(integer) 3
127.0.0.1:6379> LRANGE list01 0 -1
1) "999"
2) "666"
3) "5"
127.0.0.1:6379> LINSERT list01 after 666 333
(integer) 4
127.0.0.1:6379> LRANGE list01 0 -1
1) "999"
2) "666"
3) "333"
4) "5"
性能总结
- 它是一个字符串链表,左右都可以插入添加
- 如果list不存在则创建新list
- 如果键已经存在则增加内容
- 如果值全部移除则list消失
- 链表的操作无论对左还是右的效率都极高,但是对中间的元素操作效率很惨;
Set(集合)
- redis的Set是一个String类型的无序集合,他是通过hashtable实现;
使用
- sadd set value1,value2:往set中增加value,value如果重复不会加入
- smembers set:显示set的所有元素
- sismenber set value:判断元素是否是set的元素,是则返回1否则返回0
127.0.0.1:6379> SADD set01 1 2 3 1 2 3
(integer) 3
127.0.0.1:6379> SMEMBERS set01
1) "1"
2) "2"
3) "3"
127.0.0.1:6379> SISMEMBER set01 1
(integer) 1
127.0.0.1:6379> SISMEMBER set01 x
(integer) 0
- scard set:获取set中元素的个数
127.0.0.1:6379> SCARD set01
(integer) 3
- srem set value:删除set中元素为value的值
127.0.0.1:6379> srem set01 3
(integer) 1
127.0.0.1:6379> SMEMBERS set01
1) "1"
2) "2"
127.0.0.1:6379>
- srandmember set n:随机出n个元素,默认出一个
127.0.0.1:6379> SMEMBERS set01
1) "0"
2) "1"
3) "2"
4) "3"
5) "4"
6) "5"
7) "6"
8) "7"
9) "8"
10) "9"
127.0.0.1:6379> SRANDMEMBER set01
"4"
127.0.0.1:6379> SRANDMEMBER set01
"9"
127.0.0.1:6379> SRANDMEMBER set01
"1"
127.0.0.1:6379> SRANDMEMBER set01 3
1) "6"
2) "8"
3) "9"
- spop set:从set中出栈一个元素
127.0.0.1:6379> SMEMBERS set01
1) "0"
2) "1"
3) "2"
4) "3"
5) "4"
6) "5"
7) "6"
8) "7"
9) "8"
10) "9"
127.0.0.1:6379> spop set01
"5"
127.0.0.1:6379> spop set01
"6"
127.0.0.1:6379> SMEMBERS set01
1) "0"
2) "1"
3) "2"
4) "3"
5) "4"
6) "7"
7) "8"
8) "9"
- smove set01 set02 value:将set01中的value值移到set02中
127.0.0.1:6379> SMEMBERS set01
1) "0"
2) "1"
3) "2"
4) "3"
5) "4"
6) "7"
7) "8"
127.0.0.1:6379> SMEMBERS set02
1) "z"
2) "y"
3) "x"
127.0.0.1:6379> SMOVE set01 set02 1
(integer) 1
127.0.0.1:6379> SMEMBERS set01
1) "0"
2) "2"
3) "3"
4) "4"
5) "7"
6) "8"
127.0.0.1:6379> SMEMBERS set02
1) "z"
2) "1"
3) "y"
4) "x"
- sdiff set01 set02:取set01跟set02的差集(在set01中不在set02中)
127.0.0.1:6379> sadd set01 1 2 3 4 5
(integer) 5
127.0.0.1:6379> sadd set02 1 2 a b c
(integer) 5
127.0.0.1:6379> SDIFF set01 set02
1) "3"
2) "4"
3) "5"
- sunion set01 set02:取set01跟set02的并集
127.0.0.1:6379> SUNION set01 set02
1) "3"
2) "1"
3) "2"
4) "5"
5) "4"
6) "b"
7) "a"
8) "c"
- sinter set01 set02 :取set01根set02的交集
127.0.0.1:6379> SINTER set01 set02
1) "1"
2) "2"
Zset(sorted set:有序集合)
- redis zset和set一样也是string类型元素的集合切不允许有重复成员;
- 不同的是每个元素都会关联一个double类型的分数
- redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但是分数却可以重复;
结构
redis配置文件中用来控制zset到底是使用ziplist(压缩双向链表)还是skiplist(跳表)的参数:
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
zset-max-ziplist-entries zset使用ziplist存储的时候,最大限制存储entries的个数
zset-max-ziplist-value zset使用ziplist存储的时候,每个节点最大存储字节数
违反上述两个限制条件,均会导致zset将ziplist的数据结构切换为skiplist数据结构
而zset使用ziplist的原因,主要是出于在零散数据量少的时候,节省内容的占用
使用
- zadd zset01 score1 v1 score2 v2…:设置zset01的每个元素并附带分数
- zrange zset01 0 -1 (withscores):显示所有的元素之(附带分数)
127.0.0.1:6379> zadd zset01 60 v1 70 v2 80 v3 90 v4 100 v5
(integer) 5
127.0.0.1:6379> ZRANGE zset01 0 -1
1) "v1"
2) "v2"
3) "v3"
4) "v4"
5) "v5"
127.0.0.1:6379> ZRANGE zset01 0 -1 withscores
1) "v1"
2) "60"
3) "v2"
4) "70"
5) "v3"
6) "80"
7) "v4"
8) "90"
9) "v5"
10) "100"
- zrangebyscore zset01 score1 score2:取zset01中分数在score1跟score2之间的值
- zrangebyscore zset01 (score1 (score2:取zset01中分数大于score1跟小于score2的值
- zrangebyscore zset01 score1 score2 limit n m :取zset01中分数在score1根score2之间的值,并从中取下标为n(包含)的值开始取m个元素
127.0.0.1:6379> ZRANGEBYSCORE zset01 70 90
1) "v2"
2) "v3"
3) "v4"
127.0.0.1:6379> ZRANGEBYSCORE zset01 70 (90
1) "v2"
2) "v3"
127.0.0.1:6379> ZRANGEBYSCORE zset01 (70 (90
1) "v3"
127.0.0.1:6379> ZRANGEBYSCORE zset01 70 90 limit 1 2
1) "v3"
2) "v4"
- zrem zset01 v:移除zset01中值为v的值
127.0.0.1:6379> ZRANGE zset01 0 -1
1) "v1"
2) "v2"
3) "v3"
4) "v4"
5) "v5"
127.0.0.1:6379> ZREM zset01 100
(integer) 0
127.0.0.1:6379> zrem zset01 v1
(integer) 1
127.0.0.1:6379> ZRANGE zset01 0 -1
1) "v2"
2) "v3"
3) "v4"
4) "v5"
127.0.0.1:6379>
- zcard zset01:获取zset01中元素个数(不包含分数)
127.0.0.1:6379> zcard zset01
(integer) 4
- zcount zset01 score1 score2:统计zset01中score1到score2的值得个数
127.0.0.1:6379> ZCOUNT zset01 60 80
(integer) 2
- zrank zset01 v:获取zset01的v的下标值
- zscore zset01 v:获取zset01的v的分数
- zrevrank zset01 v:获取zset01的v的逆序下标
127.0.0.1:6379> ZRANGE zset01 0 -1 withscores
1) "v2"
2) "70"
3) "v3"
4) "80"
5) "v4"
6) "90"
7) "v5"
8) "100"
127.0.0.1:6379> ZRANK zset01 v3
(integer) 1
127.0.0.1:6379> zscore zset01 v3
"80"
127.0.0.1:6379> ZREVRANK zset01 v3
(integer) 2
- zrevrange zset01 0 -1 :逆序取所有的zset01 的元素值
127.0.0.1:6379> ZREVRANGE zset01 0 -1
1) "v5"
2) "v4"
3) "v3"
4) "v2"
- zrevrangebyscore zset01 score1 score2:取zset01中分数从score1到score2的值,注意:这里是按顺序从score1到score2并不是取大于score1小于score2的值
127.0.0.1:6379> ZREVRANGEBYSCORE zset01 60 90
(empty list or set)
127.0.0.1:6379> ZREVRANGEBYSCORE zset01 90 60
1) "v4"
2) "v3"
3) "v2"
127.0.0.1:6379> ZREVRANGEBYSCORE zset01 90 60 withscores
1) "v4"
2) "90"
3) "v3"
4) "80"
5) "v2"
6) "70"
从哪儿去获取redis命令
redis.conf
单位
include
general
- Daemonize
- pidfile
- port
- tcp-backlog
- timeout
- bind
- tcp-keepalive
- loglevel
- logfile
- syslog-enabled
- syslog-ident
- syslog-facility
- databases
snapshotting 快照
- 默认快照位置在安装目录,与redis.conf同级(不是备份的redis.conf,是自带的)
- 检查redis是否启动的三种方式:
- ps -ef | grep redis
- lsof -i :6379
- netstat -l |grep 6379
- save 秒钟 次数:表示如果在秒钟内操作了多少次则重新生成一次dump.rdb文件,默认有三种;
- save 900 1:表示900秒(15分钟)改动过一次
- save 300 10:表示300秒(5分钟)改动过10次
- save 60 10000:表示60秒(1分钟)改动过1万次
- redis中直接调用save命令可以立即备份,但是这样备份数据其他存数据的过程全部阻塞,可以使用bgsave这样既可以同时备份数据也可以同时存数据;
127.0.0.1:6379> set k1 v1 OK 127.0.0.1:6379> save OK
relication 复制
security安全
- config set requirepass password:设置密码,这样每次执行命令之前都必须执行auth password才能执行(只需要执行一次即可);
- auth password:验证密码
- config set requirepass “”:设置密码为空则不需要密码
limits 限制
- maxclients:最大客户端数
- maxmemory:最大内存 bytes
- maxmemory-policy:淘汰策略(指的是到达了maxmemory之后,怎么淘汰数据)
- noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
- allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。
- allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。
- volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。
- volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
- volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。
- 与过期策略(指的是key通过expire设置了过期时间到期后,redis怎么处理)比较:
- 定时过期:每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。
- 惰性过期:只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。
- 定期过期:每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。
(expires字典会保存所有设置了过期时间的key的过期时间数据,其中,key是指向键空间中的某个键的指针,value是该键的毫秒精度的UNIX时间戳表示的过期时间。键空间是指该Redis集群中保存的所有键。)
Redis中同时使用了惰性过期和定期过期两种过期策略。
- maxmemory-samples:样本数
append only mode 追加
RDB (redis database)
- rdb:在指定的时间间隔内将数据快照写入磁盘,恢复时将快照文件直接写入内存
- redis会单独创建(fork)一个子进程来进行持久化,会先将数据放入临时文件,然后整个持久化过程结束了,再用这个临时文件替换原dump文件,整个过程中,主进程时不进行io操作的,这就确保了极高的性能,如果需要大规模的数据恢复,且对数据恢复的完整性要求不是非常的高,rdb比aof方式更加高效,rdb的缺点是最后一次持久化的数据可能丢失;
- fork:复制一个跟当前进程一模一样的进程,并作为当前进程的子进程;
- 具体配置可参看配置文件中snapshot一节;
- 优势:
- 适合大规模数据的恢复(相比于aof速度更快),对数据完整性跟一致性要求不高
- 劣势:
- 在一定时间内做一次备份,如果redis备份前故障,则会丢失最后一次备份的数据;
- fork的时候内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑;
AOF(append only file)
- 以日志的形式记录每个写操作,将redis执行过的所有写指令记录下来(不记录读指令),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,;
- appendonly.aof文件跟dump.rdb文件可以同时存在,但是会先搜索aof文件;
- aof文件如果由于故障导致文件数据错误可以使用redis-check-aof --fix appendonly.aof修复
[root@localhost bin]# redis-check-aof --fix appendonly.aof
0x 8b: Expected prefix '1', got: '*'
AOF analyzed: size=192, ok_up_to=139, diff=53
This will shrink the AOF from 192 bytes, with 53 bytes, to 139 bytes
Continue? [y/N]: y
Successfully truncated AOF
- 重写:AOF采用文件追加模式,文件会越来越大,为了避免这种情况,新增了重写机制,当AOF文件的大小超过指定的阈值时,redis会启动AOD内容压缩,只保留可以恢复数据的最小指令集;
- 重写原理:AOF持续增长而过大时,会fork一条新进程将文件重写(也是先写到临时文件,再rename),遍历新进程内存中的数据,每条记录有一条set语句;重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令重新写了一个新的aof文件,这点跟快照类似;
- 触发机制:当aof大小是上次rewrite后的大小的一倍且文件大于64M的时候触发;
- 三种重写模式(也是其优势):
- appendfsync always:只有要数据改变立刻记录到文件中,消耗性能
- appendfsync everysec:每秒记录一次,一秒内宕机则丢失一秒内的数据(容易找回);
- appendfsync no:不同步
- 劣势:
- 相同的数据集的数据而言aof文件要远大于rdb文件,恢复速度慢与rdb;
- aof运行效率要慢于rdb,每秒同步策略较好,不同步效率跟rdb相同
redis的事务
- 序列化命令,在队列中,一次性,顺序性,排他性的执行一串命令
- 常用命令
- multi:开始事务
- exec:执行事务
127.0.0.1:6379> MULTI OK 127.0.0.1:6379> set k1 v1 QUEUED 127.0.0.1:6379> set k2 v2 QUEUED 127.0.0.1:6379> get k2 QUEUED 127.0.0.1:6379> set k3 v3 QUEUED 127.0.0.1:6379> exec 1) OK 2) OK 3) "v2" 4) OK
- discard:取消事务
127.0.0.1:6379> MULTI OK 127.0.0.1:6379> set k1 v1 QUEUED 127.0.0.1:6379> set k2 v2 QUEUED 127.0.0.1:6379> set k3 v33 QUEUED 127.0.0.1:6379> DISCARD OK 127.0.0.1:6379> get k3 "v3"
- watch key1,key2. …:监视一个或者多个key当事务执行前这个key被其他命令改动,则事务被打断;
- unwatch:取消对所有key的监视
- 当有一个命令出错时,整个事务取消
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> getset k3
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> set k5 v5
QUEUED
127.0.0.1:6379> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k5
(nil)
- 当有一个命令出错,只出错的命令不执行,其余正常执行
127.0.0.1:6379> mget k1 k2 k3
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> INCR k1
QUEUED
127.0.0.1:6379> set k2 22
QUEUED
127.0.0.1:6379> set k3 33
QUEUED
127.0.0.1:6379> set k4 44
QUEUED
127.0.0.1:6379> EXEC
1) (error) ERR value is not an integer or out of range
2) OK
3) OK
4) OK
127.0.0.1:6379> mget k1 k2 k3 k4
1) "v1"
2) "22"
3) "33"
4) "44"
- 对于3,4两点的理解,3可以理解成java中的检查时异常,4可以理解成运行时异常,这样可以可理解成redis部分支持事务
- 通过watch命令在事务执行前监控了多个key,如果在watch之后有任何key发生变化,则整个事务都将被放弃,同时返回nullmulti-bulk应答已通知失败
- 一旦unwatch或者exec之后所有的监控锁都会被取消
redis复制
how
- 配从不配主:一个客户端建立起来就是主机,但是可以将多个主机变成从机配到同一个主机下面,使用slaveof ip 端口命令来分配从机,使用info replication来显示主从信息
127.0.0.1:6381> SLAVEOF 127.0.0.1 6379
OK
127.0.0.1:6381> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:7
master_sync_in_progress:0
slave_repl_offset:2239
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:42
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=2267,lag=0
slave1:ip=127.0.0.1,port=6381,state=online,offset=2267,lag=0
master_repl_offset:2267
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:2266
- 当主机死了之后,从机原地待命,还是slave,知道主机恢复从新恢复主从关系;但是当从机死了之后,从机恢复需要再配置成从机,否则自己是master;
- 薪火相传:master下挂一个slave,slave下面还可以继续挂slave,一次类推,可以有效的减轻master的压力;
- 反客为主:master死了之后,可以将其中的slave使用slaveof no one来变成master,然后将其他slave挂在他上面,原master恢复之后还是master只不过只有一个主机没有从机;
复制原理
- slave连接成功之后像master发送一个sync同步命令
- master接受到命令传送整个数据文件给到slave用以完成一次同步(全量同步)
- master陆续将新的接受的修改命令以及数据传到slave完成同步(增量同步)
- 但是一旦重新连接还是要执行一次全量同步
- 复制的缺点:复制有一定的延迟,如果从机很多,传递的效率更低更慢
哨兵模式
- 在自定义/myredis目录下面新建sentinel.conf,名字不能出错
- 然后配置哨兵
sentinel monitor host6379(随便填写,一般主机名称即可) 127.0.0.1(ip地址) 6380(端口) 1(投票大于1则成为主机)
- 然后启动哨兵
redis-sentinel /myredis/sentinel.conf
- 哨兵启动之后,如果master死了,则剩下的slave自动选取票数大于1的成为新的master,如果原master回来则会变成slave挂在新的master下面
结合eclipse使用
- 引入redis相关jar包;