文章目录
前言
本文将通过由浅入深的方式介绍Redis相关的知识。从0开始,一步步带您深入了解redis的相关特性,并最终应用到实践当中。
一、Redis是什么?
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
Redis 可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
官网:https://redis.io/
官网的中文版:http://www.redis.cn/
下载地址:https://download.redis.io/releases/redis-6.2.6.tar.gz
二、为什么要用Redis?Redis有哪些应用场景?
1.为什么要用Redis
性能高
完全基于内存,使用C语言编写,网络层使用epoll解决高并发问题,单线程模型避免了线程上下文切换及竞争条件。数据类型丰富
五种基本类型String、List、Hash、Set、Sorted Set,还有几种特殊类型:Bitmap、HyperLogLog(基数统计)、Stream(流)、Geospatial index(地理位置索引)。功能丰富
如发布订阅功能可实现简单的消息队列、Pipeline将多条命令放到一个管道里一块执行减少网络开销、可以使用Lua脚本创建具有原子性的命令集合、提供可选的内存过期策略、自动故障转移等。支持持久化
Redis提供了两种持久化策略:RDB和AOF。RDB可以将内存中的快照每隔一段时间保存到磁盘当中,AOF可以将每条执行的命令依次追加到磁盘文件中。高可用和分布式
Redis提供了主从复制、哨兵机制以及cluster模式来支持高可用。支持多种语言
支持但不限于Java、PHP、Python、Ruby、Lua、Nodejs、C、C++、Go等等。Redis各语言下的客户端实现服务器足够简单
不依赖外部库、单线程模型、代码优雅
2.Redis常见应用场景
1.缓存系统可以将热点数据存储在redis当中,并且结合expire过期时间可以进行缓存更新操作。
2.计数器、限流、全局id主要利用了incr和incrby命令的原子性递增的特性。计数器:比如网站播放量、转发数评论数;限流:比如限制用户的访问次数,接口的调用次数;全局id:分库分表的场景,可以从redis中拿到全局唯一的id。
3.消息队列系统 redis有三种方式实现消息队列:利用list的blpop/brpop实现阻塞队列;利用pub/sub实现发布订阅模型;利用stream实现可持久化的支持Ack机制的消息队列。
4.排行榜 使用sorted可以实现对数据的分值进行排序。
5.社交网络 比如实时聊天(pub/sub)、好友关系(set)等都可以借助redis来实现。
6.地理信息定位 redis的Geo可以做诸如“附近的人”,“城市距离计算”等。
7.活跃用户统计 可以使用bitmap相关的命令将指定时间段的用户活跃情况统计出来。
8.独立总数统计 使用hyperloglog可以用极小的空间以极高的效率估计出一个集合的总数。
9.分布式锁 利用redis的setnx命令实现,setnx:"set if not exists"只有不存在才能设置上值,使用的时候可以结合过期时间防止死锁。
10.抽奖 主要利用set集合相关的命令,srandmember key [count]
随机取出一个或指定数量(count)的元素,如果count>0表示不放回的抽取,count<0表示放回的抽取(可以被重复抽取到)。也可使使用spop key [count]
命令,删除并返回一个或指定数量的元素。
三、Linux安装Redis
这里我们介绍两种方式来安装Linux。由于apt安装后的文件较为分散,不利于管理和理解,所以建议使用源码方式安装。
1.从源码安装Redis
1.1 从Redis官网下载最新稳定版源码
wget https://download.redis.io/redis-stable.tar.gz
1.2 解压缩
tar -zxvf redis-stable.tar.gz
1.3 移动到/usr/local/redis文件夹
sudo mv redis-stable /usr/local/redis
1.4 编译
cd /usr/local/redis
make
编译需要一点时间,编译完成如下图所示。编译完成之后会在src文件夹下面生成一些可执行文件(redis-server
,redis-cli
等等。利用这些文件,我们可以完成服务的启动、连接等操作,但通常我们会进行下一步的安装操作)。
1.4 安装
make PREFIX=/usr/local/redis install
PREFIX的作用是让安装后的文件都放在/usr/local/redis文件夹下,方便卸载。如果不加这个参数的话,可执行文件会安装到/usr/loca/bin下,库文件会安装到/usr/local/lib下,公共文件会放到/usr/local/share下。安装完成后,在/usr/local/redis下面可以看到一个bin目录,里面放置着redis的可执行服务,后面我们会详细介绍里面的内容。
2.从官方apt存储库安装Redis
可以从官方 packages.redis.io
APT 存储库安装 Redis 的最新稳定版本。将存储库添加到apt索引,更新它,然后安装:
2.1 将存储库添加到apt索引
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
echo “deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main” | sudo tee /etc/apt/sources.list.d/redis.list
2.2 安装
sudo apt-get update
sudo apt-get install redis
这种方式安装的redis,各个文件分散在不同的文件夹。比如:
redis-server
,redis-cli
等命令放到了/usr/bin
目录下redis.conf
默认配置文件放到了/etc/redis
目录下redis.log
默认日志文件放到了/var/log/redis
目录下redis.pid
进程id文件放在了/run/redis.pid
- redis的主目录默认是
/var/lib/redis
文件夹
四、Redis的基本使用
1、启动redis服务
/usr/local/redis/bin/redis-server& /usr/local/redis/redis.conf
找到安装完成之后的redis-server
可执行文件,以及要使用的redis.conf
配置文件,在shell中使用如上命令即启动redis服务。redis-server
后面的&
符号表示以后台的守护进程的方式运行。也可以直接修改redis.conf中的daemonize no
改成daemonize yes
达到同样的目的。
注:了解一下redis.conf中几个简单的配置
bind 127.0.0.1
表示只有本机才能连这个redis服务
protected-mode yes
表示开启保护模式,配合bind选项可以设置只允许指定的外部ip地址访问这个服务。
port 6379
表示这个服务使用的端口号是6379
daemonize yes
表示以后台守护进程的方式运行服务
2、使用redis-cli连接redis服务
/usr/local/redis-cli -h localhost -p 6379
启动redis-cli默认连接 本机的6379端口,也可以指定要连接的主机和端口以便远程连接redis服务。连接成功之后输入ping
命令,服务端会返回PONG
。
五、Redis的数据类型及其常用命令
通过上面的介绍我们已经了解到,redis并不是简单的String类型的key-value存储,还包含着丰富的数据结构,接下来我们就挨个介绍一下这几种数据结构以及它们所包含的常用命令。
1、String类型
字符串类型是redis最基本的值类型,其实现是二进制安全的,可以包含任意类型的数据,比如:图片类型或者序列化对象。一个字符串值类型最多能存储512MB字节的内容。String类型有三种内部编码:int,embstr,raw。Redis会自动根据值类型选择合适的编码。
SET key value [EX seconds] [PX milliseconds] [NX|XX]
解释:设置key的值为value
EX:过期时间,单位秒。PX:毫秒级过期时间。NX:值不存在才能设置。XX:值存在才能设置。GET key
解释:获取字符串类型key的值SETEX key seconds value
解释:设置key的值为value,并在seconds秒后过期SETNX key value
解释:如果key不存在,则设置key的值为valueMSET key value [key value ...]
解释:原子的一次性设置多个key-value值,如果存在则更新MGET key [key ...]
解释:返回所有指定的key的value,如果不存在返回nil。MSETNX key value [key value ...]
解释:原子性的设置多个key-value值,只要有一个key存在,则都不执行。SETRANGE key offset value
解释:从key对应的原字符串的offset处开始覆盖value字符串。GETRANGE key start end
解释:返回key对应值从start到end位置的子串。负的位移表示从尾部开始的下标,比如-1表示最后一个字符,-2表示倒数第二个,以此类推。STRLEN key
解释:返回key的String类型value的长度。GETSET key value
解释:设置key的值为value,并返回原来的值。APPEND key value
解释:追加value值到key对应的原来的value值的尾部。
以下是bitmap类型的命令,因为实际类型也是String类型,只不过把每个字符按照实际的8位二进制位进行操作,所以放在一块介绍一下。
SETBIT key offset value
解释:设置key对应offset处的值位value,value可以是0或者1.GETBIT key offset
解释:获取key对应string在offset处的bit值,当offset超出长度或者key不存在时总返回0.BITPOS key bit [start] [end]
解释:获取字符串里面第一个被设置成1或者0的bit位。参数bit可以时1或者0,start和end表示要从第start字节开始,到第end字节结束。BITCOUNT key [start end]
解释:统计字符串被设置成1的bit数。start和end仍然表示的是字节。BITOP operation destkey key [key ...]
解释:对一个或多个保存二进制位的字符串key进行位元操作,并把计算结果保存到destkey上。operation代表的操作可以是AND
、OR
、NOT
、XOR
。
数值类型的操作。
INCR key
解释:对存储在指定key的数值执行原子的加1操作。DECR key
解释:对存储在指定key的数值执行原子的减1操作。INCRBY key increment
解释:将key对应的数字加increment。DECRBY key decrement
解释:将key对应的数字减decrement。INCRBYFLOAT key increment
解释:将key对应的浮点数增加浮点数increment。
127.0.0.1:6379> set name genie EX 20 NX #设置key=name,value=genie,过期时间20秒,不存在才能设置成功
OK
127.0.0.1:6379> set name genie EX 20 XX #由于key=name的键已存在,所以参数XX执行不成功
(nil)
127.0.0.1:6379> ttl name #查看key=name的键还有多长时间过期
(integer) 15
127.0.0.1:6379> setex name2 60 weizhuang
OK
127.0.0.1:6379> ttl name2
(integer) 45
127.0.0.1:6379> setnx name2 tianming
(integer) 0
127.0.0.1:6379> flushdb #清楚数据库中所有的key
OK
127.0.0.1:6379> keys * #查看数据库中的所有key
(empty array)
127.0.0.1:6379> mset key1 value1 key2 value2 key3 value3
OK
127.0.0.1:6379> keys *
1) "key2"
2) "key3"
3) "key1"
127.0.0.1:6379> mget key1 key2 key3
1) "value1"
2) "value2"
3) "value3"
127.0.0.1:6379> setrange key3 2 new
(integer) 6
127.0.0.1:6379> get key3
"vanew3"
127.0.0.1:6379> getrange key3 2 -1
"new3"
127.0.0.1:6379> strlen key3
(integer) 6
127.0.0.1:6379> getset key3 hello
"vanew3"
127.0.0.1:6379> append key3 " world"
(integer) 11
127.0.0.1:6379> get key3
"hello world"
127.0.0.1:6379> setbit bitkey 1 1
(integer) 0
127.0.0.1:6379> getbit bitkey 1
(integer) 1
127.0.0.1:6379> bitpos bitkey 1
(integer) 1
127.0.0.1:6379> bitcount bitkey
(integer) 1
127.0.0.1:6379> setbit bitkey2 0 1
(integer) 0
127.0.0.1:6379> bitop and bitkey3 bitkey bitkey2
(integer) 1
127.0.0.1:6379> getbit bitkey3 0
(integer) 0
127.0.0.1:6379> set number 0
OK
127.0.0.1:6379> incr number
(integer) 1
127.0.0.1:6379> get number
"1"
127.0.0.1:6379> decr number
(integer) 0
127.0.0.1:6379> get number
"0"
127.0.0.1:6379> incrby number 10
(integer) 10
127.0.0.1:6379> decrby number 2
(integer) 8
2、List类型
Redis列表是通过Linked List实现的双向线性链表,元素按照插入顺序排序,向链表的头部和尾部添加新元素的时间复杂度是常量级的,缺点是查询的时间复杂度是O(N)。
LPUSH key value [value ...]
解释:将所有给定的值依次插入到链表的头部。LPOP key
解释:移除并返回key对应的list的第一个元素。RPUSH key value [value ...]
解释:将所有给定的值依次添加到链表的尾部。RPOP key
解释:移除并返回key对应的list的最后一个元素。LPUSHX key value [value ...]
解释:如果key对应list存在,则向链表的头部插入元素。RPUSHX key value [value ...]
解释:如果key对应的list存在,则向链表的尾部插入元素。RPOPLPUSH source destination
解释:从source列表的尾部弹出一个元素放到destination列表的头部。
应用:可以用来做安全的消息队列防止消息丢失;如果source和destination相同的话可以实现循环链表。LRANGE key start stop
解释:返回存储在key的列表中start到stop范围内的元素。偏移量从0开始计算,如果是负数表示从尾部开始计数,最后一个预算是-1。LLEN key
解释:返回存储在key的列表的长度。LINDEX key index
解释:返回存储在key的列表中下标为index(从0开始)位置的元素。LSET key index value
解释:设置存储在key的列表中下标为index位置的值为value.LINSERT key BEFORE|AFTER pivot value
解释:把value插入存于key的列表中在基准值pivot的前面或后面。LREM key count value
解释:从存于key的列表里移除前count次出现的值为value的元素。count>0从头往尾移除;count<0从尾往头移除;count=0移除所有。LTRIM key start stop
解释:修剪key存储的列表,保证列表只包含start到stop之间的元素。BLPOP key [key ...] timeout
解释:在超时时间内阻塞式从左边弹出列表元素。BRPOP key [key ...] timeout
解释:在超时时间内阻塞式从右边弹出列表元素。BRPOPLPUSH source destination timeout
解释:BRPOPLPUSH 是RPOPLPUSH的阻塞版本。
127.0.0.1:6379> lpush userlist user1 user2 user3
(integer) 3
127.0.0.1:6379> lrange userlist 0 -1
1) "user3"
2) "user2"
3) "user1"
127.0.0.1:6379> lpop userlist
"user3"
127.0.0.1:6379> lrange userlist 0 -1
1) "user2"
2) "user1"
127.0.0.1:6379&g