Redis Nosql not only sql 泛指非关系型数据库
Nosql的四大分类 KV键值对
redis
文档型数据库(boson格式)
列存储数据库
HBase
分布式文件系统
图关系型数据库
NEO4J
redis 用途 1、内存存储、持久化,内存中是断电即失、所以说持久化很重要( rdb、aof )
2、效率高,可以用于高速缓存
3、发布订阅系统
4、地图信息分析
5、计时器、计数器(浏览量)
安装 Windows 下包 安装 运行
Linux 1、官网 下载压缩包
2、解压安装包
tar -zxvf redis-6.0.10.tar.gz
基本文件结构如下
安装gcc:yum install gcc-c++
在当前路径下make
完成后再make检查一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 [root@Shyee redis-6.0.10] cd src && make allmake[1]: Entering directory '/usr/local/redis-6.0.10/src' CC Makefile.dep Hint: It's a good idea to run ' make test ' ;) make[1]: Leaving directory ' /usr/local/redis-6.0.10/src' [root@Shyee redis-6.0.10]# make install cd src && make install make[1]: Entering directory ' /usr/local/redis-6.0.10/src' Hint: It' s a good idea to run 'make test' ;) INSTALL install INSTALL install INSTALL install INSTALL install INSTALL install make[1]: Leaving directory '/usr/local/redis-6.0.10/src' [root@Shyee redis-6.0.10]
redis的默认安装路径 user/local/bin
简单的配置 将redis文件夹下的redis.configcopy到local/bin中的rconfig文件夹(自行创建)中
设置后台启动 修改config文件中的 daemonize no
,改为yes
启动 在user/local/bin
下,redis-server rconfig/redis.conf
1 2 3 4 5 6 7 8 9 10 11 [root@Shyee bin] [root@Shyee bin] 127.0.0.1:6379> ping PONG 127.0.0.1:6379> set name Shyee OK 127.0.0.1:6379> get name "Shyee" 127.0.0.1:6379> keys * 1) "name" 127.0.0.1:6379>
如果启动不成功,则在刚刚make之后在去src中make install
一下
关闭 1 2 127.0.0.1:6379> SHUTDOWN not connected> exit
查看redis服务是否启动 1 2 3 4 [root@Shyee ~]# ps -ef|grep redis root 216409 1 0 15:49 ? 00:00:00 redis-server 127.0.0.1:6379 root 216414 216382 0 15:49 pts/1 00:00:00 redis-cli -p 6379 root 216443 216421 0 15:50 pts/2 00:00:00 grep --color=auto redis
benchmark 测试 redis 性能测试工具可选参数如下所示:
序号
选项
描述
默认值
1
-h
指定服务器主机名
127.0.0.1
2
-p
指定服务器端口
6379
3
-s
指定服务器 socket
4
-c
指定并发连接数
50
5
-n
指定请求数
10000
6
-d
以字节的形式指定 SET/GET 值的数据大小
2
7
-k
1=keep alive 0=reconnect
1
8
-r
SET/GET/INCR 使用随机 key, SADD 使用随机值
9
-P
通过管道传输 请求
1
10
-q
强制退出 redis。仅显示 query/sec 值
11
–csv
以 CSV 格式输出
12
-l
生成循环,永久执行测试
13
-t
仅运行以逗号分隔的测试命令列表。
14
-I
Idle 模式。仅打开 N 个 idle 连接并等待。
测试100个并发链接 100000个请求
1 redis-benchmark -h localhost -p 6379 -c 100 -n 100000
部分分析
基础知识 redis 默认有16个数据库
1 2 3 4 127.0.0.1:6379> SELECT 3 --选择第三个数据库 OK 127.0.0.1:6379[3]> DBSIZE --查看数据库大小 (integer) 0
set一个kv后
1 2 3 4 127.0.0.1:6379[3]> SET name Shyee OK 127.0.0.1:6379[3]> DBSIZE (integer) 1
查看所有的key
1 2 127.0.0.1:6379[3]> KEYS * 1) "name"
清空当前库
1 2 3 4 127.0.0.1:6379[3]> FLUSHDB OK 127.0.0.1:6379[3]> KEYS * (empty array)
清空全部数据库
redis 是单线程的 基于内存操作的 redis 的瓶颈是机器内存及网络带宽。
redis是c语言写的
redis 将所有的数据放在内存中的,所以使用单线程操作时效率最高的。对于内存,没有上下文切换,效率是最高的,多次读写实在一个cpu上的。
redis 的基本数据类型 基本命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 127.0.0.1:6379> set name Shyee OK 127.0.0.1:6379> SET age 12 OK 127.0.0.1:6379> EXISTS name #查看是否存在关键字 (integer) 1 127.0.0.1:6379> EXPIRE name 10 #设置过期时间 (integer) 1 127.0.0.1:6379> ttl name #查看当前k的剩余时间 (integer) 6 127.0.0.1:6379> ttl name (integer) 4 127.0.0.1:6379> ttl name (integer) 2 127.0.0.1:6379> ttl name (integer) 0 127.0.0.1:6379> ttl name #-2代表已经过期 (integer) -2 127.0.0.1:6379> get name (nil) 127.0.0.1:6379> move name 1 #将该关键字转移到1号库 (integer) 1 127.0.0.1:6379> type name #查看当前k的类型 string 127.0.0.1:6379> TYPE age string
String(字符串) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 127.0.0.1:6379> APPEND name " Hello" #字符串的拼接,如果当前key不存在,就相当于set (integer) 11 127.0.0.1:6379> GET name "Shyee Hello" 127.0.0.1:6379> STRLEN name #查看当前字符串的长度 (integer) 11 # 设计自增减 127.0.0.1:6379> set views 0 OK 127.0.0.1:6379> GET views "0" 127.0.0.1:6379> INCR views #自增 (integer) 1 127.0.0.1:6379> GET views "1" 127.0.0.1:6379> DECR views #自减 (integer) 0 127.0.0.1:6379> GET views "0" 127.0.0.1:6379> INCRBY views 10 #设置步长的增减 (integer) 10 127.0.0.1:6379> DECRBY views 8 (integer) 2 127.0.0.1:6379> GET views "2" # 截取 127.0.0.1:6379> get name "Shyee Hello" 127.0.0.1:6379> GETRANGE name 2 5 #截取2~5 "yee " 127.0.0.1:6379> GETRANGE name 0 -1 #查看全部 "Shyee Hello" # setrange 127.0.0.1:6379> set k1 abcdefg OK 127.0.0.1:6379> SETRANGE k1 2 ggg #修改第二个以后的三个字符 (integer) 7 127.0.0.1:6379> GET k1 "abgggfg" # setex(set with expire) 设置过期时间 # setnx(set if not exist) 不存在设置 127.0.0.1:6379> SETEX k2 5 "只有5秒" OK 127.0.0.1:6379> ttl k2 (integer) 3 127.0.0.1:6379> SETNX k2 "ifexist" (integer) 1 127.0.0.1:6379> SETNX k2 "ife" (integer) 0 #SET 失败,因为存在了 # 一下设置很多值 127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 k4 v4 OK 127.0.0.1:6379> KEYS * 1) "k4" 2) "k3" 3) "k2" 4) "k1" # 一下拿很多值 127.0.0.1:6379> MGET k1 k2 k3 k4 1) "v1" 2) "v2" 3) "v3" 4) "v4" 127.0.0.1:6379> MSETNX k1 vv1 k5 v5 (integer) 0 #mset是原子性的操作,要么一起成功,要么一起失败 # 对象的批量set 127.0.0.1:6379> MSET user:1:name Shyee user:1:age 13 user:3:name XY OK 127.0.0.1:6379> MGET user:3:name user:1:name user:1:age 1) "XY" 2) "Shyee" 3) "13" # 取值并设置值 127.0.0.1:6379> getset name XY #如果不存在 则返回nil (nil) 127.0.0.1:6379> GETSET name Shyee "XY" 127.0.0.1:6379> GET name "Shyee"
List redis中的list是双向链表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 127.0.0.1:6379> lpush list1 abcd (integer) 1 127.0.0.1:6379> rpush list1 aaa (integer) 2 127.0.0.1:6379> get list1 (error) WRONGTYPE Operation against a key holding the wrong kind of value # 不能直接使用get来取list中的值 127.0.0.1:6379> lrange list1 0 5 1) "abcd" 2) "aaa" 127.0.0.1:6379> lpush list1 a b c d e (integer) 7 127.0.0.1:6379> lrange list1 0 -1 1) "e" 2) "d" 3) "c" 4) "b" 5) "a" 6) "abcd" 7) "aaa" 127.0.0.1:6379> rrange 0 -1 (error) ERR unknown command `rrange`, with args beginning with: `0`, `-1`, 127.0.0.1:6379> rpop list1 2 1) "aaa" 2) "abcd" 127.0.0.1:6379> lrange list1 0 -1 1) "e" 2) "d" 3) "c" 4) "b" 5) "a" 127.0.0.1:6379> rpush o p q r s t (integer) 5 127.0.0.1:6379> lrange list1 0 -1 1) "e" 2) "d" 3) "c" 4) "b" 5) "a" 127.0.0.1:6379> rpush list1 o p q r s t (integer) 11 127.0.0.1:6379> lrange list1 0 -1 1) "e" 2) "d" 3) "c" 4) "b" 5) "a" 6) "o" 7) "p" 8) "q" 9) "r" 10) "s" 11) "t" 127.0.0.1:6379> lpop list1 5 1) "e" 2) "d" 3) "c" 4) "b" 5) "a" 127.0.0.1:6379> lrange list1 0 -1 1) "o" 2) "p" 3) "q" 4) "r" 5) "s" 6) "t" # pop到最后没值了,键就不存在了
rpoplpush :从key1 的右边pop一个值放到key2的左边
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 127.0.0.1:6379> lrange list1 0 -1 1) "o" 2) "p" 3) "q" 4) "r" 5) "s" 6) "t" 127.0.0.1:6379> lpush list2 a (integer) 1 127.0.0.1:6379> lrange list2 0 -1 1) "a" 127.0.0.1:6379> rpush list2 b c d (integer) 4 127.0.0.1:6379> lrange list2 0 -1 1) "a" 2) "b" 3) "c" 4) "d" 127.0.0.1:6379> rpoplpush list1 list2 "t" 127.0.0.1:6379> lrange list2 0 -1 1) "t" 2) "a" 3) "b" 4) "c" 5) "d" 127.0.0.1:6379> lrange list1 0 -1 1) "o" 2) "p" 3) "q" 4) "r" 5) "s"
取指定下标元素
1 2 127.0.0.1:6379> lindex list1 4 "s"
获取list长度
1 2 127.0.0.1:6379> llen list1 (integer) 5
linsert
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 127.0.0.1:6379> linsert list1 before "p" ddd (integer) 6 127.0.0.1:6379> lrange list1 0 -1 1) "o" 2) "ddd" 3) "p" 4) "q" 5) "r" 6) "s" 127.0.0.1:6379> linsert list1 after "p" aaa (integer) 7 127.0.0.1:6379> lrange list1 0 -1 1) "o" 2) "ddd" 3) "p" 4) "aaa" 5) "q" 6) "r" 7) "s"
lrem key n value
从左边删除n个value
1 2 3 4 5 6 7 8 9 127.0.0.1:6379> lrem list1 2 "aaa" (integer) 1 127.0.0.1:6379> lrange list1 0 -1 1) "o" 2) "ddd" 3) "p" 4) "q" 5) "r" 6) "s"
lset 替换
1 2 3 4 5 6 7 8 9 127.0.0.1:6379> lset list1 4 qwerewr OK 127.0.0.1:6379> lrange list1 0 -1 1) "o" 2) "ddd" 3) "p" 4) "q" 5) "qwerewr" 6) "s"
list 的数据结构 list的数据结构是quicklist
当列表中元素较少的时候会使用一块连续的存储空间,这个结构是ziplist,压缩列表
当数据量比较多的时候才会使用quicklist ,是一种双向链表
且redis 将ziplist组合起来组成quicklist