初入Redis

Redis

特点:

  1. 方便扩展
  2. 大数据量高性能
  3. 数据类型多样
  4. 传统数据库

与传统的RDBMS相比:

传统的RDBMS:
- 结构化组织
- SQL语句
- 数据和关系都在单独的表中
- 严格的一致性
- 基础的事务
NOSQL
- 不仅仅是数据库
- 没有固定的语言
- 键值对存储,列存储,文档存储,图形数据库
- 最终一致性
- CAP定理和BASE
- 三高:高性能、高并发、高可扩

3V和3高

大数据时代的3V:

海量、多样、实时

互联网需求的3高

高性能、高并发、高可扩

NOSQL的四大分类

  • KV键值对:

    • 新浪:redis

    • 美团:redis+tair

    • 阿里、百度:redis+memecache

    • Redis、OracleBDB

  • 文档型数据库(bson和json一样):

    • MongoDB(一般必须要掌握)

    • MongDB:是一个分布式文件存储的数据库,C++编写,主要用来处理大量的文档

    • conthDB

  • 列存储数据库

    • HBase
    • 分布式文件系统
  • 图关系数据库

Redis能干嘛?

  1. 内存存储、持久化,内存中是断电即失,所以说持久化很重要
  2. 效率高,可以用于高速缓存
  3. 发布订阅系统
  4. 地图信息分析
  5. 计时器、计数器(浏览量)

特性

  1. 多样的数据类型
  2. 持久化
  3. 集群
  4. 事务

测试性能

Redis-benchmark是一个压力测试工具

官方自带的性能测试工具

#测试:100个并发连接 100000请求
redis-benchmark -h localhost -p 6379 -c 100 -n 100000

Last login: Mon May  2 15:41:55 on ttys001
cds-dn417@CDS-DN417deMacBook-Pro ~ % redis-benchmark -h localhost -p 6379 -c 100 -n 100000
====== PING_INLINE ======                                                     
  100000 requests completed in 0.85 seconds
  100 parallel clients
  3 bytes payload
  keep alive: 1
  host configuration "save": 3600 1 300 100 60 10000
  host configuration "appendonly": no
  multi-thread: no

Latency by percentile distribution:
0.000% <= 0.095 milliseconds (cumulative count 3)
50.000% <= 0.495 milliseconds (cumulative count 51671)
75.000% <= 0.551 milliseconds (cumulative count 76726)
87.500% <= 0.599 milliseconds (cumulative count 88477)
93.750% <= 0.679 milliseconds (cumulative count 93883)
96.875% <= 0.903 milliseconds (cumulative count 96915)
98.438% <= 1.199 milliseconds (cumulative count 98454)
99.219% <= 2.135 milliseconds (cumulative count 99226)
99.609% <= 2.887 milliseconds (cumulative count 99612)
99.805% <= 3.271 milliseconds (cumulative count 99809)
99.902% <= 4.767 milliseconds (cumulative count 99904)
99.951% <= 5.015 milliseconds (cumulative count 99952)
99.976% <= 5.151 milliseconds (cumulative count 99977)
99.988% <= 5.215 milliseconds (cumulative count 99988)
99.994% <= 5.263 milliseconds (cumulative count 99994)
99.997% <= 5.335 milliseconds (cumulative count 99997)
99.998% <= 5.375 milliseconds (cumulative count 99999)
99.999% <= 5.391 milliseconds (cumulative count 100000)
100.000% <= 5.391 milliseconds (cumulative count 100000)

Cumulative distribution of latencies:
0.004% <= 0.103 milliseconds (cumulative count 4)
0.104% <= 0.207 milliseconds (cumulative count 104)
20.619% <= 0.303 milliseconds (cumulative count 20619)
32.896% <= 0.407 milliseconds (cumulative count 32896)
54.636% <= 0.503 milliseconds (cumulative count 54636)
89.435% <= 0.607 milliseconds (cumulative count 89435)
94.637% <= 0.703 milliseconds (cumulative count 94637)
96.237% <= 0.807 milliseconds (cumulative count 96237)
96.915% <= 0.903 milliseconds (cumulative count 96915)
97.414% <= 1.007 milliseconds (cumulative count 97414)
98.009% <= 1.103 milliseconds (cumulative count 98009)
98.471% <= 1.207 milliseconds (cumulative count 98471)
98.607% <= 1.303 milliseconds (cumulative count 98607)
98.686% <= 1.407 milliseconds (cumulative count 98686)
98.727% <= 1.503 milliseconds (cumulative count 98727)
98.755% <= 1.607 milliseconds (cumulative count 98755)
98.789% <= 1.703 milliseconds (cumulative count 98789)
98.846% <= 1.807 milliseconds (cumulative count 98846)
98.917% <= 1.903 milliseconds (cumulative count 98917)
99.023% <= 2.007 milliseconds (cumulative count 99023)
99.154% <= 2.103 milliseconds (cumulative count 99154)
99.763% <= 3.103 milliseconds (cumulative count 99763)
99.812% <= 4.103 milliseconds (cumulative count 99812)
99.967% <= 5.103 milliseconds (cumulative count 99967)
100.000% <= 6.103 milliseconds (cumulative count 100000)

Summary:
  throughput summary: 117233.30 requests per second
  latency summary (msec):
          avg       min       p50       p95       p99       max
        0.493     0.088     0.495     0.719     1.983     5.391
====== PING_MBULK ======                                                     
  100000 requests completed in 0.74 seconds
  100 parallel clients
  3 bytes payload
  keep alive: 1
  host configuration "save": 3600 1 300 100 60 10000
  host configuration "appendonly": no
  multi-thread: no

Latency by percentile distribution:
0.000% <= 0.167 milliseconds (cumulative count 2)
50.000% <= 0.399 milliseconds (cumulative count 50918)
75.000% <= 0.527 milliseconds (cumulative count 77747)
87.500% <= 0.559 milliseconds (cumulative count 88268)
93.750% <= 0.591 milliseconds (cumulative count 93809)
96.875% <= 0.647 milliseconds (cumulative count 97009)
98.438% <= 0.743 milliseconds (cumulative count 98448)
99.219% <= 1.023 milliseconds (cumulative count 99219)
99.609% <= 1.135 milliseconds (cumulative count 99619)
99.805% <= 1.175 milliseconds (cumulative count 99811)
99.902% <= 1.207 milliseconds (cumulative count 99915)
99.951% <= 1.223 milliseconds (cumulative count 99961)
99.976% <= 1.231 milliseconds (cumulative count 99977)
99.988% <= 1.239 milliseconds (cumulative count 99988)
99.994% <= 1.247 milliseconds (cumulative count 99994)
99.997% <= 1.255 milliseconds (cumulative count 99998)
99.998% <= 1.263 milliseconds (cumulative count 99999)
99.999% <= 1.279 milliseconds (cumulative count 100000)
100.000% <= 1.279 milliseconds (cumulative count 100000)

Cumulative distribution of latencies:
0.000% <= 0.103 milliseconds (cumulative count 0)
0.189% <= 0.207 milliseconds (cumulative count 189)
33.647% <= 0.303 milliseconds (cumulative count 33647)
52.055% <= 0.407 milliseconds (cumulative count 52055)
69.578% <= 0.503 milliseconds (cumulative count 69578)
95.191% <= 0.607 milliseconds (cumulative count 95191)
98.095% <= 0.703 milliseconds (cumulative count 98095)
98.762% <= 0.807 milliseconds (cumulative count 98762)
98.998% <= 0.903 milliseconds (cumulative count 98998)
99.192% <= 1.007 milliseconds (cumulative count 99192)
99.449% <= 1.103 milliseconds (cumulative count 99449)
99.915% <= 1.207 milliseconds (cumulative count 99915)
100.000% <= 1.303 milliseconds (cumulative count 100000)

Summary:
  throughput summary: 135318.00 requests per second
  latency summary (msec):
          avg       min       p50       p95       p99       max
        0.409     0.160     0.399     0.607     0.911     1.279
Error from server: MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk. Commands that may modify the data set are disabled, because this instance is configured to report errors during writes if RDB snapshotting fails (stop-writes-on-bgsave-error option). Please check the Redis logs for details about the RDB error.
cds-dn417@CDS-DN417deMacBook-Pro ~ %  

可以用select进行切换数据库

redis默认是用第一个数据库(即0号数据)

127.0.0.1:6379> select 3 #切换数据库
OK
127.0.0.1:6379[3]> dbsize #查看DB大小
(integer) 0
cds-dn417@CDS-DN417deMacBook-Pro ~ % redis-cli   #进入redis客户端       
127.0.0.1:6379> select 3 #切换到3号数据库
OK
127.0.0.1:6379[3]> set name chenjianhui #输入key为name,value为chenjianhui的键值对
OK
127.0.0.1:6379[3]> dbsize#查看3号数据库大小
(integer) 1
127.0.0.1:6379[3]> get name#获得key为name的value
"chenjianhui"
127.0.0.1:6379[3]> keys *#展示当前数据库下所有key
1) "name"
127.0.0.1:6379[3]>  flushdb#清空当前数据库,flushall为清空所有数据库
OK
127.0.0.1:6379[3]> keys *
(empty array)

为什么redis以6379作为端口号?

女明星效应

Redis是单线程的

redis基于内存操作,cpu不是redis性能瓶颈,redis

五大基本类型

string

最基本的类型、键值对、二进制安全(可以包含任意数据:图片、序列化对象)、最基本的数据类型(value最大可以放512M)

hash

键值对集合、适合存储对象、类似Java里面的Map<String,Object>

list

插入顺序、底层是链表、可插入头部或者尾部

set

字符串类型的无序集合、底层是HashTable

Zset

有序集合、每个元素都会关联一个double类型的分数、⚠️利用分数来实现顺序排列、⚠️元素唯一但是分数不唯一

#命令关键字
exists #判断当前key是否存在
move #移除当前key指定元素到n号数据库
expire #设置当前key指定元素的过期时间
ttl [key]#查看当前key还有多少秒过期,不存的key或者已经过期的key状态都为-2,-1表示永不过期
type [key]#查看当前key的对应类型

String

append [key] [value]#往key的原先值后添加value,返回字符串长度;若当前key不存在就相当于set一个key
strlen [key] #查看key的字符串长度
incr [key] #+1
decr [key] #-1
incrby [key] [counts]#自增counts值
decrby [key] [counts]#自减。。。
127.0.0.1:6379> GETRANGE [key] [start] [end]#获取字符串的范围,若end为0则获取全部字符串
127.0.0.1:6379> SETRANGE [key] [offset] [value]#从offset位置,将原有字符串改成value值,后续值不变
#过期时间
127.0.0.1:6379> setex [key] [seconds] [value]#设置key的过期时间
127.0.0.1:6379> setnx [key] [value]#分布式锁中常用,如果原key不存在则可设置成功返回1,原key存在则失败返回0
#批量设置、获取
127.0.0.1:6379> mset key [key ...]#查看多个key
127.0.0.1:6379> mget key [key ...]#设置多个键值对
127.0.0.1:6379> msetnx key value [key value ...]#与setnx原理相同,原子性操作
# 传统对象缓存 
set user:1 value(json数据) 
set user:1 {name:chenjianhui,age:3} 
# 可以用来缓存对象 
mset user:1:name zhangsan user:1:age 2 
mget user:1:name user:1:age
# getset(先get再set) # =================================================== 
127.0.0.1:6379> getset db mongodb 
# 没有旧值,返回 nil (nil) 
127.0.0.1:6379> get db "mongodb" 
127.0.0.1:6379> getset db redis 
# 返回旧值 mongodb "mongodb" 
127.0.0.1:6379> get db "redis"

应用场景:计数器、统计多单位的数量、粉丝数、对象存储

List

默认像双向链表,默认从左往右读。

基本的数据类型,列表

在redis里,可以用list实现栈、队列等等

所有的list命令都是用l开头

#--插入--
#LPUSH,类似于从左边进行入栈操作
127.0.0.1:6379> LPUSH list 1 #将一个值或多个值插入到列表头部(左)
(integer) 1
127.0.0.1:6379> LPUSH list 2
(integer) 2
127.0.0.1:6379> LPUSH list 3
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "3"
2) "2"
3) "1"
#3 2 1
127.0.0.1:6379> LRANGE list 0 1
1) "3"
2) "2"
#RPUSH,从右边入队,类似于从右边进行入栈操作
127.0.0.1:6379> RPUSH list 4
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "3"
2) "2"
3) "1"
4) "4"
#3 2 1 4
#--移除--
#LPOP
127.0.0.1:6379> LPOP list #移除的同时会输出被移除的数据
"3"
#RPOP
127.0.0.1:6379> LRANGE list 0 -1
1) "2"
2) "1"
3) "4"
4) "6"
127.0.0.1:6379> RPOP list#移除的同时会输出被移除的数据
"6"
127.0.0.1:6379> LRANGE list 0 -1
1) "2"
2) "1"
3) "4"
#LINDEX,获取某个集合的下表为index的值
127.0.0.1:6379> LINDEX list 0
"2"
# llen 用于返回列表的长度。
127.0.0.1:6379> LLEN list
(integer) 3
#LRem 移除指定的值,移除list集合中指定个数的value,精确匹配
127.0.0.1:6379> LREM list 2 2
(integer) 1
127.0.0.1:6379> LREM [key] [count] [element]
#trim截断,让列表只保留区间内的元素,不在指定区间之内的元素都将被删除
 127.0.0.1:6379> Rpush mylist "hello"
(integer) 1
127.0.0.1:6379> Rpush mylist "hello2"
(integer) 2
127.0.0.1:6379> Rpush mylist "hello3"
(integer) 3
127.0.0.1:6379> LTRIM mylist  0 1 #从左边开始截取
OK
127.0.0.1:6379> LRANGE mylist 0 -1
1) "hello"
2) "hello2"
# rpoplpush 移除列表的最后一个元素,并将该元素添加到另一个列表并返回。
127.0.0.1:6379> rpush mylist "hello" 
(integer) 1 
127.0.0.1:6379> rpush mylist "foo" 
(integer) 2 
127.0.0.1:6379> rpush mylist "bar" 
(integer) 3 
127.0.0.1:6379> rpoplpush mylist myotherlist "bar" 
127.0.0.1:6379> lrange mylist 0 -1 
1) "hello" 
2) "foo" 
127.0.0.1:6379> lrange myotherlist 0 -1 
1) "bar"
# lset key index value 将列表 key 下标为 index 的元素的值设置为 value 。
127.0.0.1:6379> exists list # 对空列表(key 不存在)进行 LSET 
(integer) 0 
127.0.0.1:6379> lset list 0 item # 报错
(error) ERR no such key

127.0.0.1:6379> lpush list value1#存在则更新,不存在则报错
(integer) 1
127.0.0.1:6379> lrange 0 -1
(error) ERR wrong number of arguments for 'lrange' command
127.0.0.1:6379> LRANGE list 0 -1
1) "value1"
127.0.0.1:6379> lset list 0 new
OK
127.0.0.1:6379> LRANGE list 0 -1
1) "new"
# linsert key before/after pivot value 用于在列表的元素前或者后插入元素。 
# 将值 value 插入到列表 key 当中,位于值 pivot 之前或之后。
127.0.0.1:6379> LINSERT list before new chenjianhui
(integer) 2
127.0.0.1:6379> LINSERT list after new i
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "chenjianhui"
2) "new"
3) "i"

性能分析:

  • 它是一个字符串链表,left,right 都可以插入添加
  • 如果键不存在,创建新的链表
  • 如果键已存在,新增内容
  • 如果值全移除,对应的键也就消失了。空链表,也代表不存在
  • 链表的操作无论是头和尾效率都极高,但假如是对中间元素进行操作,效率就很惨淡了。

应用场景

消息队列、栈、

问题一:如果底层是链表的话,insert操作也是在链表上操作的吗?如果是,不用担心数据过多导致性能下降吗?

Set

#sadd 增加元素 127.0.0.1:6379> sadd key member [member ...]
127.0.0.1:6379> sadd myset hello
(integer) 1
127.0.0.1:6379> sadd myset chenjianhui
(integer) 1
#SMEMBERS key 查看key中所有值
127.0.0.1:6379> SMEMBERS myset
1) "hello"
2) "chenjianhui"
# sismember 命令判断成员元素是否是集合的成员。
127.0.0.1:6379> SISMEMBER myset hello
(integer) 1
127.0.0.1:6379> SISMEMBER myset 1
(integer) 0
# scard,获取集合里面的元素个数
127.0.0.1:6379> scard myset
(integer) 2
# srem key value 用于移除集合中的一个或多个成员元素 1成功0失败
127.0.0.1:6379> SREM myset hello
(integer) 1
127.0.0.1:6379> SREM myset 1
(integer) 0
# srandmember key 命令用于返回集合中的一个随机元素。
127.0.0.1:6379> SRANDMEMBER myset 2
1) "chenjianhui"
127.0.0.1:6379> SRANDMEMBER myset 0
(empty array)
# spop key 用于移除集合中的指定 key 的一个或多个随机元素
127.0.0.1:6379> SMEMBERS myset
1) "2"
2) "1"
3) "3"
4) "chenjianhui"
5) "4"
127.0.0.1:6379> spop myset 2 #随机移除myset中的两个元素
1) "2"
2) "chenjianhui"
# smove SOURCE DESTINATION MEMBER 
# 将指定成员 member 元素从 source 集合移动到 destination 集合。
127.0.0.1:6379> SMOVE myset myset1 1
(integer) 1
127.0.0.1:6379> SMEMBERS myset1
1) "1"
#数字集合类
差集: sdiff 交集: sinter 并集: sunion
127.0.0.1:6379> sadd k1 1
(integer) 1
127.0.0.1:6379> sadd k1 2
(integer) 1
127.0.0.1:6379> sadd k1 3
(integer) 1
127.0.0.1:6379> sadd k2 3
(integer) 1
127.0.0.1:6379> sadd k2 4
(integer) 1
127.0.0.1:6379> sadd k2 4
(integer) 0
127.0.0.1:6379> sadd k2 5
(integer) 1
#差集sdiff
127.0.0.1:6379> sdiff k1 k2#减去k1中与k2相同的元素,返回k1中的剩余元素
1) "1"
2) "2"
#交集sinter
127.0.0.1:6379> sinter k1 k2
1) "3"
#并集sunion
127.0.0.1:6379> sunion k1 k2
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"

应用场景:在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis还为集合提供了求交集、并集、差集等操作,可以非常方便的实现如共同关注、共同喜好、二度好友等功能,对上面的所有集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中。(六度分割理论)

Hash

Map集合,key-Map集合:key-,此时值是一个map集合

# hset、hget 命令用于为哈希表中的字段赋值 。 
#hset key field value [field value ...]
127.0.0.1:6379> hset m1 k1 chenjianuhi
(integer) 1
127.0.0.1:6379> hset m1 k2 24
(integer) 1
#hget key field
(error) ERR wrong number of arguments for 'hget' command
127.0.0.1:6379> hget m1 k1
"chenjianuhi"
127.0.0.1:6379> hget m1 k2
"24"
# hmset、hmget 同时将多个field-value对设置到哈希表中。会覆盖哈希表中已存在的字段。 
127.0.0.1:6379> HMSET m1 k4 kk k5 k6
OK
127.0.0.1:6379> hmget m1 k3 k4 k1
1) "liaozilin"
2) "kk"
3) "chenjianuhi"
# hgetall 用于返回哈希表中,所有的字段和值。 
127.0.0.1:6379> HGETALL m1
 1) "k1"
 2) "chenjianuhi"
 3) "k2"
 4) "24"
 5) "k3"
 6) "liaozilin"
 7) "k4"
 8) "kk"
 9) "k5"
10) "k6"
# hdel 用于删除哈希表 key 中的一个或多个指定字段
127.0.0.1:6379> HDEL m1 k5 k4
(integer) 2
127.0.0.1:6379> HGETALL m1
1) "k1"
2) "chenjianuhi"
3) "k2"
4) "24"
5) "k3"
6) "liaozilin"
# hlen 获取哈希表中字段的数量。
127.0.0.1:6379> HLEN m1
(integer) 3
# hexists 查看哈希表的指定字段是否存在。1成功0失败
127.0.0.1:6379> HEXISTS m1 k1
(integer) 1
# hkeys 获取哈希表中的所有域(field)。 
# hvals 返回哈希表所有域(field)的值。
127.0.0.1:6379> HKEYS m1
1) "k1"
2) "k2"
3) "k3"
127.0.0.1:6379> hvals m1
1) "chenjianuhi"
2) "24"
3) "liaozilin"
# hincrby 为哈希表中的字段值加上指定增量值。
127.0.0.1:6379> HSet m2 k1 1
(integer) 1
127.0.0.1:6379> HINCRBY m2 k1 5
(integer) 6
127.0.0.1:6379> HINCRBY m2 k1 -10
(integer) -4
# hsetnx 为哈希表中不存在的的字段赋值 。 1成功0失败
127.0.0.1:6379> HSETNX m2 k1 5
(integer) 0
127.0.0.1:6379> HSETNX m2 k3 1
(integer) 1

应用场景:变更的数据(尤其是用户信息的保存、经常变动的信息)hash更适合于对象的存储,string更适合于字符串的存储

ZSet

在set的基础上增加了一个值,用于排序

在set基础上,加一个score值。之前set是k1 v1 v2 v3,现在zset是 k1 score1 v1 score2 v2

# zadd 将一个或多个成员元素及其分数值加入到有序集当中。 
# zrange 返回有序集中,指定区间内的成员
127.0.0.1:6379> zadd myset 1 "one" 
(integer) 1 
127.0.0.1:6379> zadd myset 2 "two" 3 "three" 
(integer) 2
127.0.0.1:6379> ZRANGE s1 0 -1
1) "one"
2) "two"
3) "three"
# zrangebyscore 返回有序集合中指定分数区间的成员列表。有序集成员按分数值递增(从小到大) 次序排列。
127.0.0.1:6379> ZRANGEBYscore salary -inf +inf withscores#withscores会显示分数
1) "liaozilin"
2) "200"
3) "chenjianhui"
4) "500"
5) "xiaoming"
6) "2500"
127.0.0.1:6379> ZRANGEBYscore salary -inf +inf #递增序列
1) "liaozilin"
2) "chenjianhui"
3) "xiaoming"
127.0.0.1:6379> ZREVRANGE salary 0 -1 withscores #递减序列
1) "xiaoming"
2) "2500"
3) "chenjianhui"
4) "500"
5) "liaozilin"
6) "200"
# zrem 移除有序集中的一个或多个成员
127.0.0.1:6379> ZREM salary xiaoming
(integer) 1
127.0.0.1:6379> ZRANGE salary 0 -1
1) "liaozilin"
2) "chenjianhui"
# zcard 命令用于计算集合中元素的数量。
127.0.0.1:6379> zcard salary
(integer) 2
# zcount 计算有序集合中指定分数区间的成员数量。
# zrank 返回有序集中指定成员的排名。其中有序集成员按分数值递增(从小到大)顺序排列。
127.0.0.1:6379> zrank salary chenjianhui
(integer) 1 #返回排名
# zrevrank 返回有序集中成员的排名。其中有序集成员按分数值递减(从大到小)排序。
127.0.0.1:6379> zrevrank salary chenjianhui
(integer) 0 

应用场景

  1. 排列成绩
  2. 优先级
  3. 排行榜应用

posted on 2022-05-10 20:36  小陈努力努力再努力  阅读(45)  评论(0)    收藏  举报