Redis之初探
Redis是什么
- Redis是一个开源,内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。
- Key-Value格式的缓存和存储服务器;
- 数据结构服务器,它支持字符串、哈希表、列表、集合、有序集合,位图,hyperloglogs等数据类型;
- 所有数据集必须在内存中使用,磁盘是用来持久数据的。
- 是一种NoSQL数据库
Redis和Memcached的比较
- 性能和用途:Memcached优先考虑高性能和特殊响应时间,适用于简单缓存任务;Redis提供相当的性能,支持更高级的使用案例,包括异步和非阻塞I/O操作。
- 数据结构和功能:Redis支持更丰富的数据操作,而Memcached只是单一key-value内存Cache。
- 可靠性和持久化:Redis对可靠性要求较高,支持数据持久化,而Memcached只是内存缓存,对可靠性无要求。
- 集群模式:Redis原生支持集群模式,而Memcached需要依靠客户端来实现集群。
- 性能对比:Redis在存储小数据时比Memcached性能更高,但在大数据中稍有逊色。
Redis数据持久化
Redis的数据全部在内存中,如果突然宕机,数据就会全部丢失,因此必须有一种机制来保证redis的数据在发生突发状况时不会丢失、或者只丢失少量,于是必须根据一些策略来把redis内存中的数据写到磁盘中,这样当redis服务重启时,就会将硬盘中的数据恢复到内存中。Redis持久化的意义就是为了保证突然宕机,内存数据不会全部丢失。
redis有两种持久化机制
RDB和AOF。Redis4.0后支持RDB和AOF两种持久化机制混合使用,所以存在三种持久化策略。
- RDB是基于快照一次的全量备份,即周期性的把redis当前内存中的全量数据写入到一个快照文件中(周期时间可以通过配置来调整)。
- AOF(Append-only file)日志存储的是redis服务器的顺序指令序列,即对内存中数据进行修改的指令记录。当redis收到客户端修改指令后,先进行参数校验,如果校验通过,先把该指令存储到AOF日志文件中,也就是先存到磁盘,然后再执行该修改指令。
Redis是单线程还是多线程?
- Redis5及之前是单线程版本
Redis5及之前的版本使用的是单线程,也就是说只有一个 worker队列,所有的读写操作都要在这一个队列进行操作,好处是不会有线程安全问题(因为它在读写时就只有一个线程,那对于读写操作肯定没有线程安全问题啊!),但是读写 write、read 这些系统调用在Redis执行期间占用了大部分的 CPU 时间,所以这就是单线程模式的缺点。
所以也就在Redis6引入了多线程版本,接着往下看。
- Redis6开始引入多线程版本(实际上是 单线程+多线程 版本)
Redis6引入了多线程机制,但是不是说有多个worker线程同时并发读写, 而是它有 “一个 worker线程+多个IO子线程”,其实就是在 IO 就绪之后使用多线程提升读写解析数据的效率,而在 操作内存数据的时候还是用单线程。
利用这种单线程+多线程共同运作的机制,将CPU的性能显著提升了。
同时,这种机制同样不会产生线程安全问题,因为Redis在针对数据的内存操作时,是在一个公共的worker队列中实现的,先进先出,所以不会有线程安全问题。
Redis6之所以保留worker单主线程是因为单线程机制使得Redis内部实现的复杂度大大降低,而且可以保证操作的线程安全。(如果整个过程全让子线程做了,整个任务处理过程太重,就失去了原来单线程高效处理的优势了)
简单来说,就是 “请求是多线程的,但核心的内存读写操作(或者说读写计算)仍然是单线程的”。
Redis 为什么单线程还这么快?
误区1:高性能的服务器一定是多线程的!
误区2:多线程(CPU上下文会切换!)一定比单线程效率高!
- redis是将所有的数据全部放在内存中的,所以说使用单线程去操作效率就是最高的,多线程(CPU上下文会切换,耗时的操作!!!)。
- 对于内存系统来说,如果没有上下文切换效率就是最高的!多次读写都是在一个CPU上的,在内存情况下,这个就是最佳的方案!
- 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。多线程会进行CPU上下文会切换,造成时间消耗。
安装部署
因为Redis是C实现的,因此需要安装如下依赖,其次,有可能需要安装python3。
# yum install cpp
# yum install binutils
# yum install glibc
# yum install glibc-kernheaders
# yum install glibc-common
# yum install glibc-devel
# yum install gcc
# yum install make
# tar -zxvf redis-7.0.15.tar.gz
# cd redis-7.0.15
# make && make install
Hint: It's a good idea to run 'make test' ;)
make[1]: 离开目录“/data/apps/redis-7.0.15/src”
cd src && make install
make[1]: 进入目录“/data/apps/redis-7.0.15/src”
CC Makefile.dep
make[1]: 离开目录“/data/apps/redis-7.0.15/src”
make[1]: 进入目录“/data/apps/redis-7.0.15/src”
Hint: It's a good idea to run 'make test' ;)
INSTALL redis-server
INSTALL redis-benchmark
INSTALL redis-cli
make[1]: 离开目录“/data/apps/redis-7.0.15/src”
- redis的默认安装路径:/usr/local/bin
[root@jgswy-pro bin]# ll
总用量 21556
-rwxr-xr-x. 1 root root 5205488 5月 28 21:03 redis-benchmark
lrwxrwxrwx. 1 root root 12 5月 28 21:03 redis-check-aof -> redis-server
lrwxrwxrwx. 1 root root 12 5月 28 21:03 redis-check-rdb -> redis-server
-rwxr-xr-x. 1 root root 5422896 5月 28 21:03 redis-cli
lrwxrwxrwx. 1 root root 12 5月 28 21:03 redis-sentinel -> redis-server
-rwxr-xr-x. 1 root root 11441032 5月 28 21:03 redis-server
- redis默认不是后台启动,需要修改配置文件可以后台启动。
# cp /data/apps/redis-7.0.15/redis.conf /data/apps/redis-7.0.15/redis.conf.bak
# vi /data/apps/redis-7.0.15/redis.conf
daemonize yes #守护进程,修改为yes后即可后台运行
requirepass 123321 #密码,设置后访问Redis必须输人密码
# redis-server /data/apps/redis-7.0.15/redis.conf
# ss -tul
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
udp UNCONN 0 0 127.0.0.1:323 *:*
udp UNCONN 0 0 [::1]:323 [::]:*
tcp LISTEN 0 128 *:ssh *:*
tcp LISTEN 0 100 127.0.0.1:smtp *:*
tcp LISTEN 0 128 127.0.0.1:6379 *:*
tcp LISTEN 0 128 [::]:ssh [::]:*
tcp LISTEN 0 128 [::]:hbci [::]:*
tcp LISTEN 0 100 [::1]:smtp [::]:*
tcp LISTEN 0 128 [::]:9115 [::]:*
tcp LISTEN 0 128 [::]:websm [::]:*
tcp LISTEN 0 128 [::1]:6379 [::]:*
tcp LISTEN 0 128 [::]:jetdirect [::]:*
[root@jgswy-pro ~]#
配置文件
1、网络配置
2、通用配置
3、快照
持久化,在规定的时间内,执行了多少次操作,则会持久化到文件.rdb.aof
redis 是内存数据库,如果没有持久化,那么数据断电及失!
4、安全
配置redis密码
# redis-cli -p 6379
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> CONFIG GET requirepass
1) "requirepass"
2) ""
127.0.0.1:6379> CONFIG SET requirepass "P@ssw0rd"
OK
127.0.0.1:6379> CONFIG GET requirepass #获取密码
1) "requirepass"
2) "P@ssw0rd"
127.0.0.1:6379> ping
(error) NOAUTH Authentication required.
127.0.0.1:6379> AUTH P@ssw0rd #输入密码
OK
127.0.0.1:6379> ping
PONG
5、限制客户端
6、aof配置
常用命令
- 测试登录库
# redis-cli -p 6379
127.0.0.1:6379> set name test
OK
127.0.0.1:6379> get name
"test"
127.0.0.1:6379>
- redis默认有16个库(0-15),默认使用的是0,可以用select进行切换。每个数据库互相隔离。
# redis-cli -p 6379
127.0.0.1:6379> SELECT 6 #切换到数据库6
OK
127.0.0.1:6379[6]> DBSIZE #查看数据库大小
(integer) 0
127.0.0.1:6379[6]> KEYS * #查看数据库所有的key
(empty array)
127.0.0.1:6379[6]> flushdb #清空当前库的内容
OK
127.0.0.1:6379[6]> select 0
OK
127.0.0.1:6379> KEYS *
1) "myhash"
2) "mylist"
3) "name"
4) "key:__rand_int__"
5) "counter:__rand_int__"
127.0.0.1:6379> select 2
OK
127.0.0.1:6379[2]> flushall #清空所有库的内容
OK
127.0.0.1:6379[2]> select 0
OK
127.0.0.1:6379> keys *
(empty array)
# redis-cli -p 6379
127.0.0.1:6379> SET name xiaoming
OK
127.0.0.1:6379> KEYS *
1) "name"
127.0.0.1:6379> SET age 1 #插入数据
OK
127.0.0.1:6379> KEYS *
1) "name"
2) "age"
127.0.0.1:6379> EXISTS name #判断name是否存在,存在返回1,不存在返回0
(integer) 1
127.0.0.1:6379> EXISTS name1
(integer) 0
127.0.0.1:6379> move name 1 #将name从当前库移动到库1
(integer) 1
127.0.0.1:6379> set name xioaming
OK
127.0.0.1:6379> get name
"xioaming"
127.0.0.1:6379> expire name 10 #设置key的过期时间10秒,倒计时10秒后数据过期
(integer) 1
127.0.0.1:6379> ttl name #查看当前key的时间
(integer) 2
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> set name xiaoming
OK
127.0.0.1:6379> type name #查看当前key的数据类型
string
并发测试
redis提供了一款测试工具redis-benchmark
redis-benchmark 参数
-h:指定主机名
-p:指定端口,默认6379
-c:指定并发连接数
-n:指定请求数
-d:以字节形式指定SET/GET值的数据大小
测试100个并发连接,每个并发100000个请求
# redis-benchmark -h localhost -p 6379 -c 100 -n 100000
====== PING_INLINE ======
100000 requests completed in 1.36 seconds #100000个请求
100 parallel clients #100个并行客户端
3 bytes payload #每次写入3个字节
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.247 milliseconds (cumulative count 2)
50.000% <= 0.663 milliseconds (cumulative count 53433)
75.000% <= 0.687 milliseconds (cumulative count 78832)
87.500% <= 0.711 milliseconds (cumulative count 88427)
93.750% <= 1.015 milliseconds (cumulative count 93767)
96.875% <= 1.423 milliseconds (cumulative count 96926)
98.438% <= 1.623 milliseconds (cumulative count 98501)
99.219% <= 1.719 milliseconds (cumulative count 99234)
99.609% <= 1.783 milliseconds (cumulative count 99621)
99.805% <= 2.095 milliseconds (cumulative count 99805)
99.902% <= 2.599 milliseconds (cumulative count 99903)
99.951% <= 2.951 milliseconds (cumulative count 99952)
99.976% <= 3.135 milliseconds (cumulative count 99976)
99.988% <= 3.303 milliseconds (cumulative count 99988)
99.994% <= 3.391 milliseconds (cumulative count 99994)
99.997% <= 3.439 milliseconds (cumulative count 99997)
99.998% <= 3.479 milliseconds (cumulative count 99999)
99.999% <= 3.495 milliseconds (cumulative count 100000)
100.000% <= 3.495 milliseconds (cumulative count 100000) #所有请求在3.495毫秒完成
Summary:
throughput summary: 73367.57 requests per second #每秒处理73367.57个请求
latency summary (msec):
avg min p50 p95 p99 max
0.716 0.240 0.663 1.175 1.695 3.495
...
====== SET ======
100000 requests completed in 1.33 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.303 milliseconds (cumulative count 3)
50.000% <= 0.671 milliseconds (cumulative count 57052)
75.000% <= 0.687 milliseconds (cumulative count 77451)
87.500% <= 0.703 milliseconds (cumulative count 92613)
93.750% <= 0.711 milliseconds (cumulative count 95469)
96.875% <= 0.719 milliseconds (cumulative count 97002)
98.438% <= 0.735 milliseconds (cumulative count 98636)
99.219% <= 0.767 milliseconds (cumulative count 99254)
99.609% <= 0.855 milliseconds (cumulative count 99635)
99.805% <= 1.023 milliseconds (cumulative count 99808)
99.902% <= 1.871 milliseconds (cumulative count 99903)
99.951% <= 2.175 milliseconds (cumulative count 99952)
99.976% <= 2.351 milliseconds (cumulative count 99976)
99.988% <= 2.479 milliseconds (cumulative count 99988)
99.994% <= 2.551 milliseconds (cumulative count 99994)
99.997% <= 2.583 milliseconds (cumulative count 99997)
99.998% <= 2.607 milliseconds (cumulative count 99999)
99.999% <= 2.623 milliseconds (cumulative count 100000)
100.000% <= 2.623 milliseconds (cumulative count 100000)
Cumulative distribution of latencies:
0.000% <= 0.103 milliseconds (cumulative count 0)
0.003% <= 0.303 milliseconds (cumulative count 3)
0.030% <= 0.407 milliseconds (cumulative count 30)
0.067% <= 0.503 milliseconds (cumulative count 67)
0.257% <= 0.607 milliseconds (cumulative count 257)
92.613% <= 0.703 milliseconds (cumulative count 92613)
99.412% <= 0.807 milliseconds (cumulative count 99412)
99.722% <= 0.903 milliseconds (cumulative count 99722)
99.794% <= 1.007 milliseconds (cumulative count 99794)
99.833% <= 1.103 milliseconds (cumulative count 99833)
99.850% <= 1.207 milliseconds (cumulative count 99850)
99.860% <= 1.303 milliseconds (cumulative count 99860)
99.866% <= 1.407 milliseconds (cumulative count 99866)
99.870% <= 1.503 milliseconds (cumulative count 99870)
99.874% <= 1.607 milliseconds (cumulative count 99874)
99.880% <= 1.703 milliseconds (cumulative count 99880)
99.893% <= 1.807 milliseconds (cumulative count 99893)
99.910% <= 1.903 milliseconds (cumulative count 99910)
99.928% <= 2.007 milliseconds (cumulative count 99928)
99.941% <= 2.103 milliseconds (cumulative count 99941)
100.000% <= 3.103 milliseconds (cumulative count 100000)
Summary:
throughput summary: 75075.07 requests per second #每秒处理75075个请求
latency summary (msec):
avg min p50 p95 p99 max
0.673 0.296 0.671 0.711 0.751 2.623
...
参考
https://blog.csdn.net/Awwwze/article/details/115396745
https://blog.csdn.net/Wong_H/article/details/126196774
https://blog.csdn.net/Awwwze/article/details/115396745