redis基于内存,存储对象k/v,workder 单线程串行处理请求(依次读取请求,计算,返回结果),使用epoll 实现io并发。用于替换传统项目CRUD. 优点:对于像mysql需要加锁串行处理请求的业务,使用redis代替不用反复的请求锁会提升性能。 缺点:一个worker不能充分利用服务器多cpu性能。(redis 6.*可以将计算与io过程分散到多个线程,worker thread负责计算,读请求/返回数据交给IO thread)
类型 | 作用 |
---|---|
string | 基本类型,就是普通的set和get,做简单的kv缓存,可以对数值字符串进行数值计算,场景session共享,对象(小文件,小图片转成字符串存储到redis);数值计算,秒杀场景限流计数。bitmap场景,任意时间窗口内,某用户的登录次数setbit u1:2020 364 1 ,BITCOUNT u1:2020 0 -1 |
list | (可以快速访问list的头尾,双向链表)可以通过list存储一些列表型的数据结构,类似粉丝列表、文章的评论列表之类的东西.可以通过lrange命令,就是从某个元素开始读取多少个元素,可以基于list实现分页查询,这个很棒的一个功能,基于redis实现简单的高性能分页,可以做类似微博那种下拉不断分页的东西,性能高,就一页一页走 |
hash | hash类的数据结构,主要是用来存放一些对象,把一些简单的对象给缓存起来,后续操作的时候,你可以直接仅仅修改这个对象中的某个字段的值 |
set | 无序集合,自动去重。直接基于set将系统里需要去重的数据扔进去,自动就给去重了,如果你需要对一些数据进行快速的全局去重,你当然也可以基于jvm内存里的HashSet进行去重,但是如果你的某个系统部署在多台机器上呢?得基于redis进行全局的set去重。可以基于set使用交集、并集、差集的操作,比如交集,可以把两个人的粉丝列表做一个交集,看看俩人的共同好友是谁 |
sorted set zset | 排序的set,去重但是可以排序,写进去的时候给一个分数,自动根据分数排序,最大的特点是有个分数可以自定义排序规则。比如说你要是想根据时间对数据排序,那么可以写入进去的时候用某个时间作为分数,人家自动给你按照时间排序了。排行榜:将每个用户以及其对应的什么分数写入进去,zadd board score username,接着zrevrange board 0 99,就可以获取排名前100的用户; |
yum安装
[root@oracledb ~]# yum install epel-release
[root@oracledb ~]# yum install redis
[root@oracledb ~]# systemctl start redis
使用nc 链接redis
#$数字表示数据的字符数
[root@oracledb ~]# nc 127.0.0.1 6379
set test1 'hello world'
+OK
keys *
*1
$5
test1
get test1
$11
hello world
使用redis-cli连接redis
[root@oracledb ~]# redis-cli
127.0.0.1:6379> keys *
1) "test1"
127.0.0.1:6379>
127.0.0.1:6379> get test1
"hello world"
127.0.0.1:6379>
不使用第三方软件,使用shell的文件描述符连接redis
[root@oracledb ~]# exec 9<> /dev/tcp/127.0.0.1/6379
[root@oracledb ~]# echo "keys *" >& 9
[root@oracledb ~]# cat <&9
*1
$5
test1
#查看每种类型的帮助
[root@oracledb ~]# redis-cli
127.0.0.1:6379> help @list
127.0.0.1:6379> help @string
127.0.0.1:6379> help @hash
127.0.0.1:6379> help @set
实现功能:放入取出顺序:同向 -- 栈;异向-- 队列;数组,ltrim ,数据顺序与放入方法有关 场景:数据共享(作为分布式服务的数据用,区别于单服务Java hashmap),状态迁出(不在jvm中存储数据)。
127.0.0.1:6379> LPUSH t1 a b c d e f
(integer) 6
127.0.0.1:6379> LRANGE t1 0 -1
1) "f"
2) "e"
3) "d"
4) "c"
5) "b"
6) "a"
127.0.0.1:6379> rpush t1 x y z
(integer) 9
127.0.0.1:6379> LRANGE t1 0 -1
1) "f"
2) "e"
3) "d"
4) "c"
5) "b"
6) "a"
7) "x"
8) "y"
9) "z"
127.0.0.1:6379> lpop t1
"f"
127.0.0.1:6379> rpop t1
"z"
127.0.0.1:6379> LINDEX t1 2
"c"
127.0.0.1:6379> LRANGE t1 0 -1
1) "e"
2) "d"
3) "c"
4) "b"
5) "a"
6) "x"
7) "y"
hashmap场景,数据聚合信息 - hashmap操作
127.0.0.1:6379> hset u1 name aaa
(integer) 1
127.0.0.1:6379> hset u1 age 18
(integer) 1
127.0.0.1:6379> hgetall u1
1) "name"
2) "aaa"
3) "age"
4) "18"
127.0.0.1:6379> hvals u1
1) "aaa"
2) "18"
127.0.0.1:6379> hkeys u1
1) "name"
2) "age"
127.0.0.1:6379> HINCRBY u1 age 1
(integer) 19
127.0.0.1:6379> hget u1 age
"19"
set集合操作慢可以将redis根据功能多实例部署。 set 集合 、去重 、无序 (在jvm中hashset的实现是value为null的hashmap,元素变多会rehash扩容,顺序会变化) 场景:随机--抽奖,差集--你的好友也在玩什么游戏,商品推荐,好友文章阅读 - SET操作
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> sadd k1 aaa as asd asd abb bbb bb bbb
(integer) 6
127.0.0.1:6379> SMEMBERS k1
1) "asd"
2) "aaa"
3) "bbb"
4) "as"
5) "abb"
6) "bb"
127.0.0.1:6379> OBJECT encoding k1
"hashtable"
127.0.0.1:6379> type k1
set
#3返回结果不重复
127.0.0.1:6379> SRANDMEMBER k1 3
1) "as"
2) "bb"
3) "abb"
#-3返回结果会有重复
127.0.0.1:6379> SRANDMEMBER k1 -3
1) "bb"
2) "bbb"
3) "bbb"
127.0.0.1:6379> SPOP k1
"bb"
127.0.0.1:6379> SPOP k1
"as"
127.0.0.1:6379> SPOP k1
"bbb"
127.0.0.1:6379> SPOP k1
"aaa"
127.0.0.1:6379> SPOP k1
"abb"
127.0.0.1:6379> SPOP k1
"asd"
127.0.0.1:6379> SPOP k1
(nil)
zset , score排序的维度, 场景: 评论分页,排行榜,有序事件 - zset操作
127.0.0.1:6379> zadd k1 3.5 apple 7.1 orange 1.6 banana
(integer) 3
127.0.0.1:6379> ZRANGE k1 0 -1 withscores
1) "banana"
2) "1.6000000000000001"
3) "apple"
4) "3.5"
5) "orange"
6) "7.0999999999999996"
127.0.0.1:6379> ZRANK k1 apple
(integer) 1
#取出从小到大前两名
127.0.0.1:6379> ZRANGE k1 0 1
1) "banana"
2) "apple"
#取从大到小前2
127.0.0.1:6379> ZREVRANGE k1 0 1
1) "orange"
2) "apple"
#查看底层数据结构,ziplist压缩表,元素数量小于128个,所有member的长度都小于64字节
127.0.0.1:6379> OBJECT encoding k1
"ziplist"
#设置一个member的长度大于64字节,skiplist跳跃表(与单链表比牺牲空间换取时间,与红黑树效率接近,skiplist最高64层)
127.0.0.1:6379> ZADD k1 10 dsdfjshfsjdfgjdsjsdjhgsdhjgfvbsdhjbvchjsbhjfbeybfyseydfbeyjasgdhfbajkefdghaegfbjasegbfjsdssdfsdfsdfsfssfsd
(integer) 1
127.0.0.1:6379> OBJECT encoding k1
"skiplist"
持久化方式 | 特性 |
---|---|
快照 rdb | 恢复快,丢失数据多默认的持久化方式 |
日志aof | 数据完整性高、1、速度慢2、恢复时冗余数据太多(重写规避bgrewriteaof命令),默认关闭,没打开aof |
快照和aof混合使用 | 4.*版本之后,aof时先再aof文件中保存rdb全量数据,再将日志追加到aof文件后面(类似于hdfs fsimage与edits.log),通过aof-use-rdb-preamble yes启用 |
aof 频率控制 | 配置 |
---|---|
每个操作写日志 | 开启后redis性能降低很多(老版本开启aof ,rdb不再起作用,redis4.*之前)appendfssync always |
每秒钟 ,os缓冲 刷写,一个buffer,丢失小于一个buffer | 默认的方式 appendfsync everysec |
os缓冲 刷写,一个buffer | 配置参数appendfssync no |
aof重写触发配置参数 | 含义 |
---|---|
auto-aof-rewrite-percentage 100 | 超过上次100%就重写 |
auto-aof-rewrite-min-size 64mb | 达到64兆重写 |
redis-benchmark命令,这里我实在个人虚拟机上测试的,-c并发的连接数,-n总请求数,-q静默模式 -t使用什么指令测试
本机自测试(不同主机,不同网络性能都会受影响)
[root@oracledb ~]# redis-benchmark -c 4000 -n 100000 -q -t set
SET: 31338.14 requests per second
[root@oracledb ~]# redis-benchmark -c 1 -n 100000 -q -t set
SET: 35423.31 requests per second
[root@oracledb ~]# redis-benchmark -c 10 -n 100000 -q -t set
SET: 60132.29 requests per second
[root@oracledb ~]# redis-benchmark -c 100 -n 100000 -q -t set
SET: 64599.48 requests per second
[root@oracledb ~]# redis-benchmark -c 300 -n 100000 -q -t set
SET: 46019.32 requests per second
集群用来解决2个问题:1单点故障;2redis单机容量与并发量。
redis 主从复制 (强一致性,可用性差;弱一致性,可用性好,会有数据差异) redis分片: 客户端算法分发到不同redis(取模分片); proxy实现(Twemproxy); redis cluster