redis背景
- 概述
- Windows安装
- Linux安装
- 基础知识说明
- 五大数据类型
- Redis键(key)
- 字符串String
概述
Redis是什么
Redis:REmote DIctionary Server(远程字典服务器)
是完全开源免费的,用C语言编写的,遵守BSD协议,是一个高性能的(Key/Value)分布式内存数据
库,基于内存运行,并支持持久化的NoSQL数据库,是当前最热门的NoSQL数据库之一,也被人们称为
数据结构服务器
Redis与其他key-value缓存产品有以下三个特点
- Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使
用。 - Redis不仅仅支持简单的 key-value 类型的数据,同时还提供list、set、zset、hash等数据结构的存
储。 - Redis支持数据的备份,即master-slave模式的数据备份。
Redis能干嘛
内存存储和持久化:redis支持异步将内存中的数据写到硬盘上,同时不影响继续服务
取最新N个数据的操作,如:可以将最新的10条评论的ID放在Redis的List集合里面
发布、订阅消息系统
地图信息分析
定时器、计数器
…
特性
数据类型、基本操作和配置
持久化和复制,RDB、AOF
事务的控制
…
常用网站
https://redis.io/官网
http://www.redis.cn 中文网
Windows安装
下载地址:https://github.com/dmajkic/redis/downloads ( 素材提供 )
解压到自己电脑的环境目录即可
![在这里插入图片描述](
双击 redis-server.exe 启动即可
通过客户端去访问 redis-cli
# 测试基本的set设值
127.0.0.1:6379> set name zhangsan
OK
# 取出存储的值
127.0.0.1:6379> get name
"zhangsan"
127.0.0.1:6379>
重要提示
根据官网的介绍,推荐使用linux部署。http://www.redis.cn/topics/introduction
Linux安装
下载地址 https://download.redis.io/releases/redis-6.0.6.tar.gz
安装步骤
启动
修改daemonize 属性为yes ,默认为no
- A、redis.conf配置文件中daemonize守护线程,默认是NO。
- B、daemonize是用来指定redis是否要用守护线程的方式启动。
daemonize 设置yes或者no区别
- daemonize:yes
redis采用的是单进程多线程的模式。当redis.conf中选项daemonize设置成yes时,代表开启
守护进程模式。在该模式下,redis会在后台运行,并将进程pid号写入至redis.conf选项
pidfile设置的文件中,此时redis将一直运行,除非手动kill该进程 - daemonize:no
当daemonize选项设置成no时,当前界面将进入redis的命令行界面,exit强制退出或者关闭
连接工具(putty,xshell等)都会导致redis进程退出。
启动测试一下!
# 【shell】启动redis服务
[root@192 bin]# cd /usr/local/bin
[root@192 bin]# redis-server /opt/redis-5.0.7/redis.conf
# redis客户端连接===> 观察地址的变化,如果连接ok,是直接连上的,redis默认端口号 6379
[root@192 bin]# redis-cli -p 6379
127.0.0.1:6379> ping PONG
127.0.0.1:6379> set k1 helloworld OK
127.0.0.1:6379> get k1 "helloworld"
# 【shell】ps显示系统当前进程信息
[root@192 myredis]# ps -ef|grep redis
root 16005 1 0 04:45 ? 00:00:00 redis-server
127.0.0.1:6379
root 16031 15692 0 04:47 pts/0 00:00:00 redis-cli -p 6379
root 16107 16076 0 04:51 pts/2 00:00:00 grep --color=auto redis
# 【redis】关闭连接
127.0.0.1:6379> shutdown
not connected> exit
# 【shell】ps显示系统当前进程信息
[root@192 myredis]# ps -ef|grep redis
root 16140 16076 0 04:53 pts/2 00:00:00 grep --color=auto redis
基础知识说明
redis压力测试工具-----Redis-benchmark
Redis-benchmark是官方自带的Redis性能测试工具,可以有效的测试Redis服务的性能。
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个请求,检测host为localhost 端口为6379的redis服务器性能
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
# 测试出来的所有命令只举例一个!
====== SET ======
100000 requests completed in 1.88 seconds # 对集合写入测试
100 parallel clients # 每次请求有100个并发客户端
3 bytes payload # 每次写入3个字节的数据,有效载荷
keep alive: 1 # 保持一个连接,一台服务器来处理这些请求
17.05% <= 1 milliseconds
97.35% <= 2 milliseconds
99.97% <= 3 milliseconds
100.00% <= 3 milliseconds # 所有请求在 3 毫秒内完成
53248.14 requests per second # 每秒处理 53248.14 次请求
基本数据库常识
1、默认16个数据库,类似数组下标从零开始,初始默认使用零号库
查看 redis.conf ,里面有默认的配置
databases 16
# Set the number of databases. The default database is DB 0, you can select
# a different one on a per-connection basis using SELECT <dbid> where
# dbid is a number between 0 and 'databases'-1
databases 16
2、Select命令切换数据库
127.0.0.1:6379> Select 1
OK
127.0.0.1:6379[1]>
3、Dbsize查看当前数据库的key的数量
127.0.0.1:6379[1]> dbsize
(integer) 0
4、Flushdb:清空当前库
5、Flushall:清空全部的库
为什么redis是单线程
我们首先要明白,Redis很快!官方表示,因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis
的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就
顺理成章地采用单线程的方案了!
Redis采用的是基于内存的采用的是单进程单线程模型的 KV 数据库,由C语言编写,官方提供的数据是
可以达到100000+的QPS(每秒内查询次数)。这个数据不比采用单进程多线程的同样基于内存的 KV
数据库 Memcached 差!
Redis为什么这么快?
1)以前一直有个误区,以为:高性能服务器 一定是多线程来实现的
原因很简单因为误区二导致的:多线程 一定比 单线程 效率高,其实不然!
在说这个事前希望大家都能对 CPU 、 内存 、 硬盘的速度都有了解了!
2)redis 核心就是 如果我的数据全都在内存里,我单线程的去操作 就是效率最高的,为什么呢,因为
多线程的本质就是 CPU 模拟出来多个线程的情况,这种模拟出来的情况就有一个代价,就是上下文的切
换,对于一个内存的系统来说,它没有上下文的切换就是效率最高的。redis 用 单个CPU 绑定一块内存
的数据,然后针对这块内存的数据进行多次读写的时候,都是在一个CPU上完成的,所以它是单线程处
理这个事。在内存的情况下,这个方案就是最佳方案。
因为一次CPU上下文的切换大概在 1500ns 左右。从内存中读取 1MB 的连续数据,耗时大约为 250us,
假设1MB的数据由多个线程读取了1000次,那么就有1000次时间上下文的切换,那么就有1500ns *
1000 = 1500us ,我单线程的读完1MB数据才250us ,你光时间上下文的切换就用了1500us了,我还不
算你每次读一点数据 的时间。
五大数据类型
官方文档
String (字符串类型)
String是redis最基本的类型,你可以理解成Memcached一模一样的类型,一个key对应一个value。
String类型是二进制安全的,意思是redis的string可以包含任何数据,比如jpg图片或者序列化的对象。
String类型是redis最基本的数据类型,一个redis中字符串value最多可以是512M。
Hash(哈希,类似 Java里的Map)
Redis hash 是一个键值对集合。
Redis hash 是一个String类型的field和value的映射表,hash特别适合用于存储对象。
类似Java里面的Map<String,Object>
List(列表)
Redis列表是简单的字符串列表,按照插入顺序排序,你可以添加一个元素到列表的头部(左边)或者尾
部(右边)。
它的底层实际是个链表 !
Set(集合)
Redis的Set是String类型的无序集合,它是通过HashTable实现的!
Zset(sorted set:有序集合)
Redis zset 和 set 一样,也是String类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。
Redis正是通过分数来为集合中的成员进行从小到大的排序,zset的成员是唯一的,但是分数(Score)
却可以重复。
Redis键(key)
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> set name zhangsan
OK
127.0.0.1:6379> get name
"zhangsan"
127.0.0.1:6379> keys *
1) "name"
# exists key 判断key是否存在,1表示存在,0表示不存在
127.0.0.1:6379> exists name
(integer) 1
127.0.0.1:6379> exists name1
(integer) 0
127.0.0.1:6379> set name zhangsan
OK
127.0.0.1:6379> set age 18
OK
127.0.0.1:6379> keys *
1) "age"
2) "name"
# 移动Move 命令用于将当前 Redis 数据库的 KEY 移动到给定的数据库 db 当中。
# 如果当前数据库(源数据库)和给定数据库(目标数据库)有相同名字的给定 KEY ,或者 KEY 不存在于当前数据库,那么 MOVE 没有任何效果。
127.0.0.1:6379> move name 1
(integer) 1
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> keys *
1) "name"
# 目标数据库中存在,move没有任何效果
127.0.0.1:6379> move name 1
(integer) 0
# expire key 秒钟:为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删 除。
# ttl key 查看还有多少秒过期,-1 表示永不过期,-2 表示已过期
127.0.0.1:6379> set name zhangsan
OK
127.0.0.1:6379> expire name 20
(integer) 1
127.0.0.1:6379> ttl name
(integer) 17
127.0.0.1:6379> ttl name
(integer) 15
127.0.0.1:6379> ttl name
(integer) 12
127.0.0.1:6379> ttl name
(integer) 10
127.0.0.1:6379> ttl name
(integer) 8
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379>
# type key 查看你的key是什么类型
127.0.0.1:6379> set age 18
OK
127.0.0.1:6379> type age
string
字符串String
常用命令说明
# ===================================================
# set(设置值)、get(获取值)、del(删除值)、append(追加值)、strlen(字符串长度)
# ===================================================
127.0.0.1:6379> set name zhangsan # 设置值
OK
127.0.0.1:6379> get name # 获取值
"zhangsan"
127.0.0.1:6379> del name # 删除值
(integer) 1
127.0.0.1:6379> keys * # 查看列表是否存在
(empty list or set)
127.0.0.1:6379> exists name # 通过exists查看是否存在
(integer) 0
127.0.0.1:6379> append name hello #对不存在的 key 进行 APPEND ,等同于 SET
(integer) 5
127.0.0.1:6379> append name Word # 对已存在的字符串进行 APPEND
(integer) 9
127.0.0.1:6379> get name # 查看最终值
"helloWord"
127.0.0.1:6379> strlen name # 获取字符串长度
(integer) 9
127.0.0.1:6379>
# ===================================================
# incr、decr 一定要是数字才能进行加减,+1 和 -1。
# incrby、decrby 命令将 key 中储存的数字加上指定的增量值。
# ===================================================
127.0.0.1:6379> set views 0 #设置初始值,值为数字类型
OK
127.0.0.1:6379> incr views #incr累加1
(integer) 1
127.0.0.1:6379> incr views #incr累加1
(integer) 2
127.0.0.1:6379> decr views #decr累减1
(integer) 1
127.0.0.1:6379> decr views # decr累减1
(integer) 0
127.0.0.1:6379> incrby views 10 #指定添加多少值
(integer) 10
127.0.0.1:6379> decrby views 5 #指定减少多少值
(integer) 5
127.0.0.1:6379> get views #查看最终值
"5"
127.0.0.1:6379>
# ===================================================
# range [范围]
# getrange 获取指定区间范围内的值,类似between...and的关系,从零到负一表示全部
# ===================================================
127.0.0.1:6379> set name helloword
OK
127.0.0.1:6379> get name
"helloword"
127.0.0.1:6379> getrange name 0 1
"he"
127.0.0.1:6379> getrange name 0 -1
"helloword"
127.0.0.1:6379>
# ===================================================
# setrange 设置指定区间范围内的值,格式是setrange key值 开始替换的索引位置值[offset] 具体值
# ===================================================
127.0.0.1:6379> get name #查看name值
"helloword"
127.0.0.1:6379> setrange name 0 H #替换索引位置为0的字符为H
(integer) 9
127.0.0.1:6379> get name #查看
"Helloword"
127.0.0.1:6379> setrange name 0 HELLOWORD #从索引为0开始替换,HELLOWORD
(integer) 9
127.0.0.1:6379> GET name
"HELLOWORD"
127.0.0.1:6379>
# ===================================================
# setex(set with expire)键秒值 设置key的过期时间 setex key 过期时间 value
# setnx(set if not exist) 判断key是否存在并且设置值 1为成功,0为失败。失败表示有key存在了。
# ===================================================
127.0.0.1:6379> setex name 10 xiaowang #设置name:xiaowang过期时间为10
OK
127.0.0.1:6379> get name #查看设置值
"xiaowang"
127.0.0.1:6379> ttl name # 查看剩余过期时间
(integer) 7
127.0.0.1:6379> setnx age 18 #不存在age字段时设置
(integer) 1
127.0.0.1:6379> setnx age 19 #存在age字段时设置
(integer) 0
127.0.0.1:6379> get age
"18"
# ===================================================
# mset Mset 命令用于同时设置一个或多个 key-value 对。
# mget Mget 命令返回所有(一个或多个)给定 key 的值。
# 如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil 。
# msetnx 当所有 key 都成功设置,返回 1 。
# 如果所有给定 key 都设置失败(至少有一个 key 已经存在),那么返回 0 。原子操作
# ===================================================
127.0.0.1:6379> mset k1 v1 k2 v2 #批量添加
OK
127.0.0.1:6379> keys * #查看
1) "k2"
2) "k1"
127.0.0.1:6379> mget k1 k2 #批量获取
1) "v1"
2) "v2"
# msetnx如果所有给定 key 都设置失败(至少有一个 key 已经存在),那么返回 0 。原子操作
127.0.0.1:6379> msetnx k1 v1 k2 v2 k3 v3 #再次批量条件 具有原子性
(integer) 0
127.0.0.1:6379> mget k1 k2 k3
1) "v1"
2) "v2"
3) (nil)
# 获取k3为nul
# ===================================================
# getset(先get再set)
# ===================================================
127.0.0.1:6379> getset name zhangsan # 获取旧值设置新值,没有旧值返回为null
(nil)
127.0.0.1:6379> getset name lisi #获取旧值设置新值,有旧值返回zhangsan
"zhangsan"
127.0.0.1:6379> get name #查看新值
"lisi"
127.0.0.1:6379>
String数据结构是简单的key-value类型,value其实不仅可以是String,也可以是数字。
常规key-value缓存应用:
常规计数:微博数,粉丝数等。