中文版命令学习地址(有些参数没细讲):http://www.redis.cn/commands.html
英文版命令学习地址:https://redis.io/commands
文章目录
一、安装
本次使用Docker安装使用Redis
root@zxh:~# docker pull redis # 下载redis镜像
root@zxh:~# docker run -p 6379:6379 -d redis # 启动redis容器。后台方式运行,并映射容器和主机的端口
root@zxh:~# docker ps # 查看所有正在运行的容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b4a21afd7dc8 redis "docker-entrypoint.s…" 32 seconds ago Up 31 seconds 0.0.0.0:6379->6379/tcp gracious_poincare
root@zxh:~# docker exec -it b4a21afd7dc8 /bin/bash # 启动容器
进入容器后,执行后面的操作
由于使用Docker的方式没有redis.conf配置文件,所以我们要拿到配置文件
root@b4a21afd7dc8:/data# apt update # 更新源
root@b4a21afd7dc8:/data# apt install -y vim # 安装vim编辑器
root@b4a21afd7dc8:/data# apt install -y wget # 安装wget工具
root@b4a21afd7dc8:/data# cd /usr/local/bin # 进入到redis的安装目录下
root@b4a21afd7dc8:/usr/local/bin# ls # 查看文件
docker-entrypoint.sh gosu redis-benchmark redis-check-aof redis-check-rdb redis-cli redis-sentinel redis-server
root@b4a21afd7dc8:/usr/local/bin# redis-server --version # 查看版本,然后到官网找到对应的版本下载
Redis server v=6.2.3 sha=00000000:0 malloc=jemalloc-5.1.0 bits=64 build=dc20d908b7b619b4
root@b4a21afd7dc8:/usr/local/bin# wget https://download.redis.io/releases/redis-6.2.3.tar.gz
root@b4a21afd7dc8:/usr/local/bin# tar -zxvf redis-6.2.3.tar.gz # 解压文件
root@b4a21afd7dc8:/usr/local/bin# cp ./redis-6.2.3/redis.conf /usr/local/bin/ # 拷贝里面的配置文件
root@b4a21afd7dc8:/usr/local/bin# rm -rf redis-6.2.3 # 删除文件夹
root@b4a21afd7dc8:/usr/local/bin# cp redis.conf redis.conf.bak # 备份一份配置文件
root@b4a21afd7dc8:/usr/local/bin# ls
docker-entrypoint.sh gosu redis-benchmark redis-check-aof redis-check-rdb redis-cli redis-sentinel redis-server redis.conf redis.conf.bak
为了方便后面的操作,还要安装一些操作系统的运维工具
root@b4a21afd7dc8:/data# apt install -y iproute2 # 安装ip查看工具
root@b4a21afd7dc8:/data# apt install -y procps # 安装ps查看进程工具
二、启动、关闭
1.启动
redis默认在交互式下运行,但我们希望它是后台的方式运行,因此我们要修改配置文件
root@b4a21afd7dc8:/usr/local/bin# vim redis.conf
里面大概257行,把daemonize no
改为daemonize yes
,之后启动就可以在后台正常运行
使用redis服务工具,通过指定的配置文件redis.conf
启动服务
root@b4a21afd7dc8:/usr/local/bin# redis-server redis.conf
2.查看是否启动成功
第一种方式。使用redis-cli客户端工具,查看redis服务是否启动成功。-p参数指定连接端口
root@b4a21afd7dc8:/usr/local/bin# redis-cli -p 6379
第二种方式。由于我们启动容器时使用了端口映射,所以在主机下可以查看到有关redis服务的进程信息。当然,我们更希望在容器中查看,因此,我们在主机下需要再一次启动redis容器
很可惜,docker的环境中没有ps进程查看工具,因此我们在主机下面查看
我一定要在容器中查看怎么办,可以,在redis容器中安装ps工具
root@b4a21afd7dc8:/data# apt install -y procps
3.基本使用
set
key value,用于设置字符串类型的键值对
get
key,用于获取某个键的值
keys
pattern,pattern是正则表达式,用于获取某些键
4、登陆密码
默认为空,可以添加密码
127.0.0.1:6379> config get requirepass # 获取密码,为空
1) "requirepass"
2) ""
127.0.0.1:6379> config set requirepass "123456" # 设置密码123456
OK
如果我们还在redis-cli客户端中,那么还可以继续执行命令,但是退出再重新进来后,就没有权限执行命令了
127.0.0.1:6379> ping
(error) NOAUTH Authentication required.
127.0.0.1:6379> set name zhong
(error) NOAUTH Authentication required.
可以使用auth
命令登陆
127.0.0.1:6379> auth 123456OK127.0.0.1:6379> pingPONG
5、配置命令
使用redis-cli连接之后,可以使用config get xxxkey
获取的配置值,然后可以使用config set xxxkey xxxvalue
修改值
上面修改密码时已经使用过了
6.关闭redis服务
shutdown
[NOSAVE|SAVE],关闭时可以选择是否保存本次操作的数据
正常主机编译安装的redis,若是关闭redis服务,执行shutdown命令后,只会显示not connected
注意,使用Docker的方式运行Redis服务,若是关闭服务,就会自动关闭并退出容器
再次启动redis容器
启动Redis服务,和之前一样
root@b4a21afd7dc8:/data# redis-server /usr/local/bin/redis.conf
三、redis-benchmark工具
redis-benchmark是一个性能测试工具,用于查看该主机能抗住多少并发量
可选参数如下所示:
序号 | 选项 | 描述 | 默认值 |
---|---|---|---|
1 | -h | 指定服务器主机名 | 127.0.0.1 |
2 | -p | 指定服务器端口 | 6379 |
3 | -s | 指定服务器 socket | |
4 | -c | 指定并发连接数 | 50 |
5 | -n | 指定请求数 | 10000 |
6 | -d | 以字节的形式指定 SET/GET 值的数据大小 | 3 |
7 | -k | 1=keep alive 0=reconnect | 1 |
8 | -r | SET/GET/INCR 使用随机 key, SADD 使用随机值 | |
9 | -P | 通过管道传输 <numreq> 请求 | 1 |
10 | -q | 强制退出 redis。仅显示 query/sec 值 | |
11 | –csv | 以 CSV 格式输出 | |
12 | *-l*(L 的小写字母) | 生成循环,永久执行测试 | |
13 | -t | 仅运行以逗号分隔的测试命令列表。 | |
14 | -/(i 的大写字母) | Idle 模式。仅打开 N 个 idle 连接并等待。 |
root@b4a21afd7dc8:/usr/local/bin# redis-benchmark -h localhost -p 6379 -c 100 -n 100000
测试工具开始运行后,会调用几乎所有命令进行测试,每项测试大概内容如下,以set请求为例
四、Redis的基本概念
默认有16个数据库,在redis.conf文件大概在327行有记录databases 16
,可以修改。默认使用的是0数据库
默认6379端口,大概在98行port 6379
,可以修改。
单线程运行。数据都是在内存中操作,不会发生磁盘的I/O操作,相比之下多线程切换的时间更长
1.切换数据库
select
index
2.查看数据库容量
dbsize
3.删除当前所选数据库的所有键
flushdb
[ASYNC|SYNC]
ASYNC
:异步刷新数据库SYNC
:同步刷新数据库
flushall
[ASYNC|SYNC],删除所有数据库的键
五、5种基本数据类型
一)辅助命令
1、判断某个键是否存在
exists
key [key …]
可以接多个键,存在多少个结果就是多少个
2、移动键到其他数据库
move
key dbIndex
从当前数据库移动某个键到某一个数据库,如果目标数据库已存在或者源数据库不存在,则不操作。返回值为1则成功,为0则失败。
3、设置键的过期时间
expire
key seconds
4、查看键的剩余存活时间
ttl
key
5、查看键的类型
type
key
127.0.0.1:6379> set name zhongOK127.0.0.1:6379> type namestring
二)string(字符串)
1、字符串拼接
append
key value
在尾部追加字符串,并返回新字符串的长度。如果该键不存在,就创建该键,值为空字符串,然后再执行追加操作
2、获取字符串的长度
strlen
key
127.0.0.1:6379> strlen say(integer) 10127.0.0.1:6379> get say"helloworld"
3、字符串类似数字般+1操作
incr
key
4、字符串类似数字般-1操作
decr
key
127.0.0.1:6379> set id 0OK127.0.0.1:6379> decr id(integer) -1127.0.0.1:6379> decr id(integer) -2127.0.0.1:6379> get id"-2"
5、字符串类似数字般+或 - 数字n操作
incrby
key increment
decrby
key increment
incrby也可以做到decrby的功能
127.0.0.1:6379> set test 2
OK
127.0.0.1:6379> incrby test 10
(integer) 12
127.0.0.1:6379> incrby test -8
(integer) 4
6、截取字符串
getrange
key start end
127.0.0.1:6379> get say
"helloworld"
127.0.0.1:6379> getrange say 3 5
"low"
127.0.0.1:6379> getrange say 0 -1
"helloworld"
7、从某个位置开始替换字符串
setrange
key offset value
127.0.0.1:6379> set say helloworldOK127.0.0.1:6379> setrange say 6 niubi(integer) 11127.0.0.1:6379> get say"hellowniubi"
8、如果键存在就修改值和修改过期时间
setex
key seconds value
如果键不存在就新建该键,之后设置值,再设置过期时间
127.0.0.1:6379> set name zhongOK127.0.0.1:6379> setex name 10 "xiao"OK127.0.0.1:6379> get name"xiao"127.0.0.1:6379> ttl name(integer) 4127.0.0.1:6379> get name(nil)
9、如果键不存在就创建该键值对(分布式锁常用)
setnx
key value
如果存在则不做操作
########不存在就创建######127.0.0.1:6379> get name(nil)127.0.0.1:6379> setex name 10 "xiao"OK127.0.0.1:6379> get name"xiao"########存在不做操作#########127.0.0.1:6379> set name zhongOK127.0.0.1:6379> setnx name xiao(integer) 0127.0.0.1:6379> get name"zhong"
10、同时创建多个键值对,获取多个键值对
mset
key value [key value …]
如果设置了相同的键,取最后一个
127.0.0.1:6379> keys *(empty array)127.0.0.1:6379> mset name zhong age 10 OK127.0.0.1:6379> keys *1) "age"2) "name"
mget
key [key …]
127.0.0.1:6379> mget name age1) "zhong"2) "10"
11、如果键不存在就创建多个键值对
msetnx
key value [key value …]
原子性操作,一个设置不成功,所有设置都不成功
127.0.0.1:6379> set name zhongOK127.0.0.1:6379> msetnx name xiao age 10(integer) 0127.0.0.1:6379> keys *1) "name"127.0.0.1:6379> get name"zhong"
12、先获取值,再设置值
getset
key value
先获取值,如果为空就输出nil,不为空就输出原来的值,最后设置值
127.0.0.1:6379> getset say hello(nil)127.0.0.1:6379> getset say world"hello"127.0.0.1:6379> get say"world"
设计键值对的思考
reids中没有json格式类型,如果使用字符串类型,那怎么设计
- 在服务端序列化成字符串之后保存,客户端拿到数据之后再进行反序列化
set user:1 {name:zhong,age:18}
- 把json中的键放到redis的键中,但是这样的话最好还是使用hash操作方便
mset user:1:name zhong user:1:age 18
三)list(列表)
将值放到列表中,也可以将它作为栈或者队列来使用。
1、将值放入列表中,从左边放入
lpush
key element [element …]
127.0.0.1:6379> lpush age 10 20 30 40(integer) 4127.0.0.1:6379> lpush age 50(integer) 5127.0.0.1:6379> keys *1) "age"
2、获取列表的值
lrange
key start stop
127.0.0.1:6379> lrange age 0 -1 # 取出所有值1) "50"2) "40"3) "30"4) "20"5) "10"127.0.0.1:6379> lrange age 0 21) "50"2) "40"3) "30"
3、将值放入列表中,从右边放入
rpush
key element [element …]
127.0.0.1:6379> rpush age 10 20 30 40(integer) 4127.0.0.1:6379> rpush age 50(integer) 5127.0.0.1:6379> lrange age 0 -11) "10"2) "20"3) "30"4) "40"5) "50"
4、从左边移出n个值
lpop
key [count]
127.0.0.1:6379> lrange age 0 -11) "10"2) "20"3) "30"4) "niu"5) "bi"# 从左边移除2个值127.0.0.1:6379> lpop age 21) "10"2) "20"127.0.0.1:6379> lrange age 0 -11) "30"2) "niu"3) "bi"
5、从右边移出n个值
rpop
key [count]
127.0.0.1:6379> lrange age 0 -11) "30"2) "niu"3) "bi"# 从右边移除1个值127.0.0.1:6379> rpop age 11) "bi"127.0.0.1:6379> lrange age 0 -11) "30"2) "niu"
6、获取某个索引对应的值
lindex
key index
127.0.0.1:6379> lrange age 0 -11) "10"2) "20"3) "30"4) "40"127.0.0.1:6379> lindex age 1"20"127.0.0.1:6379> lindex age -2"30"127.0.0.1:6379> lrange age 0 -1 # 内容不变,只是读取1) "10"2) "20"3) "30"4) "40"
7、查看列表的长度
llen
key
127.0.0.1:6379> llen age(integer) 4127.0.0.1:6379> lrange age 0 -11) "10"2) "20"3) "30"4) "40"
8、移除列表中的值
lrem
key count element
列表是可以存在多个相同的值的,count指定移除多少个相同的值,从左边开始算起
127.0.0.1:6379> lrange age 0 -11) "40"2) "50"3) "10"4) "20"5) "30"6) "40"127.0.0.1:6379> lrem age 2 40(integer) 2127.0.0.1:6379> lrange age 0 -11) "50"2) "10"3) "20"4) "30"
9、截取列表的部分值,剩余的值会被移除出列表
ltrim
key start stop
127.0.0.1:6379> lrange age 0 -1
1) "10"
2) "20"
3) "30"
4) "40"
5) "50"
127.0.0.1:6379> ltrim age 1 3 # 只留下了1、2、3下标的值
OK
127.0.0.1:6379> lrange age 0 -1
1) "20"
2) "30"
3) "40"
10、移除一个列表最右边的值到另一个列表的最左边
rpoplpush
source destination
如果目标列表不存在则创建,如果源列表不存在则返回nil
127.0.0.1:6379> lrange age 0 -1
1) "10"
2) "20"
3) "30"
4) "40"
5) "50"
127.0.0.1:6379> rpoplpush age id
"50"
127.0.0.1:6379> lrange age 0 -1
1) "10"
2) "20"
3) "30"
4) "40"
127.0.0.1:6379> lrange id 0 -1
1) "50"
11、修改某位索引对应的值
lset
key index element
如果该键不存在则报错
127.0.0.1:6379> lrange age 0 -11) "10"2) "20"3) "30"4) "40"127.0.0.1:6379> lset age 1 15OK127.0.0.1:6379> lrange age 0 -11) "10"2) "15"3) "30"4) "40"
12、在某个元素的前面或者后面插入值
linsert
key BEFORE|AFTER pivot element
before代表前面,after代表后面,pivot代表要查找的值
127.0.0.1:6379> lrange age 0 -11) "10"2) "15"3) "30"4) "40"127.0.0.1:6379> linsert age after "30" 35 # 在元素30的后面插入值35(integer) 5127.0.0.1:6379> lrange age 0 -11) "10"2) "15"3) "30"4) "35"5) "40"
列表的思考
原理上是一个链表,如果把里面的元素移除空了,该链表也就不存在了,所以该列表也不存在了。
在链表左右两边改动值效率是最高的,如果要操作中间的值,就需要遍历效率差
四)set(集合)
无序不重复集合
1、添加成员
sadd
key member [member …]
127.0.0.1:6379> sadd age 10 20 30 10(integer) 3127.0.0.1:6379> sadd age 40(integer) 1
2、输出所有成员
smembers
key
127.0.0.1:6379> smembers age1) "10"2) "20"3) "30"4) "40"
3、判断某个成员是否存在
sismember
key member
127.0.0.1:6379> sismember age 20 # 存在(integer) 1127.0.0.1:6379> sismember age 60 # 不存在(integer) 0
4、获取集合的成员个数
scard
key
127.0.0.1:6379> smembers age1) "10"2) "20"3) "30"4) "40"127.0.0.1:6379> scard age(integer) 4
5、移除某些成员
srem
key member [member …]
127.0.0.1:6379> smembers age1) "10"2) "20"3) "30"4) "40"127.0.0.1:6379> srem age 20 40(integer) 2127.0.0.1:6379> smembers age1) "10"2) "30"
6、随机获取n个成员
srandmember
key [count]
127.0.0.1:6379> srandmember age"40"127.0.0.1:6379> srandmember age 21) "30"2) "10"127.0.0.1:6379> srandmember age 21) "20"2) "40"127.0.0.1:6379> srandmember age 1"10"
7、随机移除n个元素
spop
key [count]
127.0.0.1:6379> smembers age1) "10"2) "20"3) "30"4) "40"5) "50"6) "60"127.0.0.1:6379> spop age 21) "50"2) "20"127.0.0.1:6379> smembers age1) "10"2) "30"3) "40"4) "60"
8、移动一个集合中的一个成员到另一个集合
smove
source destination member
如果目标集合不存在则创建,如果源集合不存在则不操作
127.0.0.1:6379> smembers age1) "10"2) "30"3) "40"4) "60"127.0.0.1:6379> smembers id(empty array)127.0.0.1:6379> smove age id 10(integer) 1127.0.0.1:6379> smembers age1) "30"2) "40"3) "60"127.0.0.1:6379> smembers id1) "10"
9、n个集合的差集
sdiff
key [key …]
以第一个集合为参照对比
127.0.0.1:6379> sadd age 10 20 30 40 50 60(integer) 6127.0.0.1:6379> sadd id 15 20 35 45 51(integer) 5127.0.0.1:6379> sdiff age id1) "10"2) "30"3) "40"4) "50"5) "60"
10、n个集合的交集
sinter
key [key …]
以第一个集合为参照对比
127.0.0.1:6379> sinter age id1) "20"
11、n个集合的并集
sunion
key [key …]
127.0.0.1:6379> sunion age id 1) "10" 2) "15" 3) "20" 4) "30" 5) "35" 6) "40" 7) "45" 8) "50" 9) "51"10) "60"
12、排序
sort
key [BY pattern] [LIMIT offset count] [GET pattern] [ASC|DESC] [ALPHA] destination
可以对集合、列表、有序集合进行排序
127.0.0.1:6379> smembers age # 打印所有成员1) "10"2) "18"3) "30"4) "42"5) "50"127.0.0.1:6379> sort age # 降序排序1) "10"2) "18"3) "30"4) "42"5) "50"127.0.0.1:6379> sort age desc # 添加desc参数升序排序1) "50"2) "42"3) "30"4) "18"5) "10"
五)hash(哈希)
hash实际是map集合,也是一个key-value,相当于多了一层key。它和string没什么太大区别。
1、添加hash
hset
key field value [field value …]
如果已存在map,再修改则失败
127.0.0.1:6379> hset user age 18 name zhong hight 2.0
(integer) 3
127.0.0.1:6379> hset user weight 100
(integer) 1
127.0.0.1:6379> hset user weight 110
(integer) 0
2、获取hash里面的值
hget
key field
127.0.0.1:6379> hget user age
"18"
127.0.0.1:6379> hget user name
"zhong"
127.0.0.1:6379> hget user hight
"2.0"
127.0.0.1:6379> hget user weight
"100"
3、设置hash多个字段的值
hmset
key field value [field value …]
看起来和hset一样,但是他可以修改map已存在的值
127.0.0.1:6379> hget user weight"100"127.0.0.1:6379> hmset user weight 110OK127.0.0.1:6379> hget user weight"110"
4、获取hash多个值
hmget
key field [field …]
hget只能获取一个map值,这个可以获取多个map值
127.0.0.1:6379> hmget user age name weight1) "18"2) "zhong"3) "110"
5、获取所有hash值
hgetall
key
map以键值对的形式显示
127.0.0.1:6379> hgetall user1) "age"2) "18"3) "name"4) "zhong"5) "hight"6) "2.0"7) "weight"8) "110"
6、删除hash中的多个字段
hdel
key field [field …]
127.0.0.1:6379> hdel user hight weight(integer) 2127.0.0.1:6379> hgetall user1) "age"2) "18"3) "name"4) "zhong"
7、查看hash的长度
hlen
key
127.0.0.1:6379> hlen user # 只有2个(integer) 2127.0.0.1:6379> hset user height 2.0 # 再添加一个map(integer) 1127.0.0.1:6379> hlen user # 有3个了(integer) 3
8、判断hash中某个字段是否存在
hexists
key field
127.0.0.1:6379> hexists user age # 存在(integer) 1127.0.0.1:6379> hexists user ages # 不存在(integer) 0
9、获取hash中所有的字段
hkeys
key
127.0.0.1:6379> hkeys user1) "age"2) "name"3) "height"
10、对hash的一个字段+n的整数操作
hincrby
key field increment
127.0.0.1:6379> hget user age"18"127.0.0.1:6379> hincrby user age 5(integer) 23127.0.0.1:6379> hincrby user age -10(integer) 13
11、对hash的一个字段+n的浮点操作
hincrbyfloat
key field increment
127.0.0.1:6379> hget user height"2.0"127.0.0.1:6379> hincrbyfloat user height 5.11"7.11"
12、不存在就创建
hsetnx
key field value
127.0.0.1:6379> hget user age"13"127.0.0.1:6379> hsetnx user age 22 # 已存在,创建失败(integer) 0127.0.0.1:6379> hsetnx user agess 22 # 不存在,创建成功(integer) 1127.0.0.1:6379> hget user age"13"127.0.0.1:6379> hget user agess"22"
六)zset(有序集合)
在set的基础上,对set的值增加了一个权值,使用该权值来排序
1、添加成员
zadd
key [NX|XX] [GT|LT] [CH] [INCR] score member [sco
127.0.0.1:6379> zadd english 1 98(integer) 1127.0.0.1:6379> zadd english 3 80(integer) 1127.0.0.1:6379> zadd english 2 85(integer) 1127.0.0.1:6379> zadd english 4 75 6 60 # 添加多个
2、获取所有的成员
zrange
key min max [BYSCORE|BYLEX] [REV] [LIMIT offset count] [WITHSCORES]
withscores代表和权值一起输出
127.0.0.1:6379> zrange english 0 -11) "98"2) "85"3) "80"4) "75"5) "60"
3、通过权值取区间内的成员
zrangebyscore
key min max [WITHSCORES] [LIMIT offset count]
min代表最小的权值可以使用-inf代表无穷小,max代表最大的权值可以使用+inf代表无穷大。withscores参数代表和权值一起输出。添加了limit之后,offset代表从那个位置开始,到offset+count位置的区间内的成员排序。
127.0.0.1:6379> zrangebyscore english -inf +inf1) "98"2) "85"3) "80"4) "75"5) "60"127.0.0.1:6379> zrangebyscore english -inf +inf withscores 1) "98" 2) "1" 3) "85" 4) "2" 5) "80" 6) "3" 7) "75" 8) "4" 9) "60"10) "6"127.0.0.1:6379> zrangebyscore english -inf +inf limit 2 21) "80"2) "75"
4、移除集合中的n个成员
zrem
key member [member …]
127.0.0.1:6379> zrange english 0 -11) "98"2) "85"3) "80"4) "75"5) "60"127.0.0.1:6379> zrem english 98 60(integer) 2127.0.0.1:6379> zrange english 0 -11) "85"2) "80"3) "75"
5、获取集合中的成员个数
zcard
key
127.0.0.1:6379> zrange english 0 -11) "85"2) "80"3) "75"127.0.0.1:6379> zcard english(integer) 3
6、获取集合某区间内的成员个数
zcount
key min max
127.0.0.1:6379> zrange english 0 -1 withscores
1) "85"
2) "2"
3) "80"
4) "3"
5) "75"
6) "4"
127.0.0.1:6379> zcount english 1 3
(integer) 2
127.0.0.1:6379> zcount english 1 4
(integer) 3
7、修改某个成员的权值
zincrby
key increment member
increment代表权值在源数值上增加多少,member代表成员的值。如果成员不存在,则新增该成员并使用设置的权值
127.0.0.1:6379> zrange english 0 -1 withscores
1) "85"
2) "2"
3) "80"
4) "3"
5) "75"
6) "4"
127.0.0.1:6379> zincrby english 5 "85"
"7"
127.0.0.1:6379> zrange english 0 -1 withscores
1) "80"
2) "3"
3) "75"
4) "4"
5) "85"
6) "7"
127.0.0.1:6379> zincrby english -5 "85"
"2"
六、三种特殊数据类型
一)geospatial(地理位置)
geo底层原理上是zset有序集合,所以可以使用zset的命令操作geo
获取地址的经纬度在线网址1:https://www.qvdv.com/tools/qvdv-coordinate.html
获取地址的经纬度在线网址2:http://www.daquan.la/jingwei/
1、添加地理位置
geoadd
key [NX|XX] [CH] longitude latitude member [longitude latitude member …]
longitude代表经度,latitude代表纬度,member代表成员名称
127.0.0.1:6379> geoadd city 121.403484 31.256177 shanghaishi(integer) 1127.0.0.1:6379> geoadd city 116.413384 39.910925 beijingshi(integer) 1
2、获取成员的位置信息
geopos
key member [member …]
127.0.0.1:6379> geopos city beijingshi shanghaishi # 获取北京市和上海市的地理位置1) 1) "116.41338318586349487" 2) "39.9109247398676743"2) 1) "121.40348285436630249" 2) "31.25617763989148301"
3、获取两个位置的距离
geodist
key member1 member2 [m|km|ft|mi]
m代表米,km代表千米,ft代表英尺,mi代表英里
127.0.0.1:6379> geodist city beijingshi shanghaishi km # 北京市和上海市的距离"1062.7281"
4、获取某个位置范围内的成员
GEORADIUS
key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
以经度longitude,纬度latitude为中心,半径为radius的范围内的key的成员。
withdist代表同时输出每个成员距离中心的距离,
单位保持一致。withcoord代表同时输出具体成员的地理位置。
count参数加具体数值表示只输出n个结果,优先选择最短的
127.0.0.1:6379> geoadd guangshang 113.575051 23.307731 tushuguan # 广商图书馆(integer) 1127.0.0.1:6379> geoadd guangshang 113.574027 23.312377 jingbeizi # 金贝子(integer) 1127.0.0.1:6379> geoadd guangshang 113.561181 23.271831 junhexiaoxue # 均和小学(integer) 1127.0.0.1:6379> geoadd guangshang 113.571134 23.313091 tangcunditie # 汤村地铁(integer) 1127.0.0.1:6379> geoadd guangshang 113.575356 23.309656 youzheng # 邮政(integer) 1# 经纬度是第一教学楼,对guangshang位置内计算,在第一教学楼300米范围内的成员127.0.0.1:6379> georadius guangshang 113.576129 23.308569 300 m1) "youzheng"2) "tushuguan"127.0.0.1:6379> georadius guangshang 113.576129 23.308569 500 m # 500米范围内的成员1) "youzheng"2) "jingbeizi"3) "tushuguan"127.0.0.1:6379> georadius guangshang 113.576129 23.308569 500 m withdist count 21) 1) "tushuguan" 2) "144.1020"2) 1) "youzheng" 2) "144.6107"
5、获取某个成员一定范围内的成员
georadiusbymember
key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
127.0.0.1:6379> georadiusbymember guangshang tushuguan 500 m1) "tushuguan"2) "youzheng"127.0.0.1:6379> georadiusbymember guangshang tushuguan 800 m1) "tushuguan"2) "tangcunditie"3) "youzheng"4) "jingbeizi"
6、使用zset的命令操作geo
geo本质上是zset,使用zset的命令操作get
127.0.0.1:6379> zrange guangshang 0 -11) "junhexiaoxue"2) "tushuguan"3) "tangcunditie"4) "youzheng"5) "jingbeizi"127.0.0.1:6379> zrem guangshang junhexiaoxue tangcunditie # 删除2个成员(integer) 2127.0.0.1:6379> zrange guangshang 0 -11) "tushuguan"2) "youzheng"3) "jingbeizi"
二)hyperloglog
基数统计的算法,不重复的元素个数,可以接受误差
常用于统计网页的访问量。传统的方法是使用set集合保存用户的id,然后统计集合中的元素个数,但是对于分布式id较长、占用空间较大,造成资源浪费,所以要解决这个问题。
hyperloglog使用的内存是固定的,占用12KB的内存,但是错误率为0.81%,但是该出错率我们可以接受
1、添加元素
pfadd
key element [element …]
127.0.0.1:6379> pfadd shouye a s d f g h j k l(integer) 1
2、统计个数
pfcount
key [key …]
127.0.0.1:6379> pfadd shouye a s d f g h j k l(integer) 1127.0.0.1:6379> pfcount shouye(integer) 9127.0.0.1:6379> pfadd golang z x c v b n m(integer) 1127.0.0.1:6379> pfcount shouye golang(integer) 16127.0.0.1:6379> pfcount golang
3、合并多个键
pfmerge
destkey sourcekey [sourcekey …]
destkey代表新的结果集,sourcekey代表源数据集
127.0.0.1:6379> pfadd c++ a s d f g h j k l(integer) 1127.0.0.1:6379> pfadd python a s c b g h j n l(integer) 1127.0.0.1:6379> pfcount c++(integer) 9127.0.0.1:6379> pfcount python(integer) 9127.0.0.1:6379> pfcount c++ python(integer) 12127.0.0.1:6379> pfmerge yuyang c++ pythonOK127.0.0.1:6379> pfcount yuyang(integer) 12
三)bitmaps
位运算存储。只有0和1两个状态。结构上,一个键可以有很多个位,每个位单独操作,且使用索引的方式操作
1、添加位的值
setbit
key offset value
127.0.0.1:6379> setbit qiandao 0 1 # 星期一签到(integer) 0127.0.0.1:6379> setbit qiandao 1 1 # 星期二签到(integer) 0127.0.0.1:6379> setbit qiandao 2 1 # 星期三签到(integer) 0127.0.0.1:6379> setbit qiandao 3 0 # 星期四没签到(integer) 0127.0.0.1:6379> setbit qiandao 4 1 # 星期五签到(integer) 0127.0.0.1:6379> setbit qiandao 5 1 # 星期六签到(integer) 0127.0.0.1:6379> setbit qiandao 6 0 # 星期日没签到(integer) 0
2、获取某个位置的值
getbit
key offset
127.0.0.1:6379> getbit qiandao 1 # 星期二的值为1,代表已签到(integer) 1127.0.0.1:6379> getbit qiandao 3 # 星期四的值为0,代表没签到(integer) 0127.0.0.1:6379> getbit qiandao 2(integer) 1
3、统计签到的天数
bitcount
key [start end]
127.0.0.1:6379> bitcount qiandao # 不加参数代表统计所有的位(integer) 5127.0.0.1:6379> bitcount qiandao 0 -1(integer) 5
七、事务
事务就是一组命令的集合。事务中的命令都会被序列化,并按照顺序执行。
传统的事务的原子性,要么同时成功,要么同时失败,但是Redis的事务不能保证原子性,只有在单条命令才能保证原子性。
事务的所有命令一个个的压进队列中,并没有立即执行,直到最后发起执行操作,才一个个顺序的执行。redis的事务没有隔离级别的概念,因此就没有脏读、幻读等概念。
redis的事务命令:
- 开启事务(multi)
- 命令1
- 命令2
- ……
- 命令n
- 执行事务(exec)
事务的操作
127.0.0.1:6379> multi # 开启事务
OK
127.0.0.1:6379(TX)> set name zhong # 命令入队列
QUEUED
127.0.0.1:6379(TX)> set age 18
QUEUED
127.0.0.1:6379(TX)> get age
QUEUED
127.0.0.1:6379(TX)> incr age
QUEUED
127.0.0.1:6379(TX)> exec # 执行事务,开始顺序执行所有命令
1) OK
2) OK
3) "18"
4) (integer) 19
放弃事务discard
127.0.0.1:6379> multi # 开启事务OK127.0.0.1:6379(TX)> set name xiao # 命令QUEUED127.0.0.1:6379(TX)> get name # 命令QUEUED127.0.0.1:6379(TX)> discard # 放弃事务OK127.0.0.1:6379> get name # 获取name的值没有改变,说明事务没有操作"zhong"
命令异常
事务中命令格式有异常,所有命令都不能执行
127.0.0.1:6379> multi # 开启事务OK127.0.0.1:6379(TX)> set id 1QUEUED127.0.0.1:6379(TX)> get id id # 命令格式有异常(error) ERR wrong number of arguments for 'get' command127.0.0.1:6379(TX)> exec # 执行事务(error) EXECABORT Transaction discarded because of previous errors.127.0.0.1:6379> get id # 获取的值为空,说明没有设置成功(nil)
事务中语法操作有异常,只有该命令不能执行成功,其他所有命令都成功。也说明Redis的事务没有原子性。
127.0.0.1:6379> multi # 开启事务OK127.0.0.1:6379(TX)> set id xxxQUEUED127.0.0.1:6379(TX)> incr id # 操作语法有误,不能对字母进行加1QUEUED127.0.0.1:6379(TX)> exec # 执行事务1) OK2) (error) ERR value is not an integer or out of range127.0.0.1:6379> get id # 获取到值,说明set命令执行成功"xxx"
八、锁
悲观锁和乐观锁
悲观锁,认为任意时刻都可能出问题,无论做什么都要加锁
乐观锁,任务什么时候都不会出问题,不会上锁。等更新数据的时候判断一下在此期间内是否有人修改过这个数据(mysql中取值时获取一下version,更新数据后写回磁盘时再判断一下version有没有改变),
监视器(watch)
127.0.0.1:6379> set money 100OK127.0.0.1:6379> set out 0OK127.0.0.1:6379> watch money # 监视money对象OK127.0.0.1:6379> multi # 事务在这里正常执行结束,money在运行期间没有发生其他进程的改动OK127.0.0.1:6379(TX)> incrby money -20QUEUED127.0.0.1:6379(TX)> incrby out 20QUEUED127.0.0.1:6379(TX)> exec1) (integer) 802) (integer) 20
正常的情况下如上正常执行,但是如果在高并发情况下,其他用户在该用户的事务过程中修改了money的值,就会导致该事务执行失败
下面模拟该行为
- 在一个客户端中监视money对象,然后开启事务,但是没有提交
127.0.0.1:6379> get money # 当前值为80"80"127.0.0.1:6379> watch money # 开始监视OK127.0.0.1:6379> multiOK127.0.0.1:6379(TX)> incrby money -50QUEUED127.0.0.1:6379(TX)> incrby out 50QUEUED# 还没有使用exec命令提交执行
- 开启另一个客户端,修改money对象
# 在主机中进入正在运行的redis容器
root@zxh:~# docker exec -it b4a21afd7dc8 /bin/bash
# 连接redis服务
root@b4a21afd7dc8:/data# redis-cli -p 6379
127.0.0.1:6379> get money
"80"
127.0.0.1:6379> set money 10000
OK
- 此时第一步中的监视器已经发现money被修改了,然后我们开始提交事务
127.0.0.1:6379> get money
"80"
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> incrby money -50
QUEUED
127.0.0.1:6379(TX)> incrby out 50
QUEUED
127.0.0.1:6379(TX)> exec # 提交执行,运行失败,返回nil
(nil)
可以发现watch其实就是一个乐观锁
在使用exec命令或者discard命令后,会自动取消监视的对象,也可以使用unwatch
命令取消监视
如果取消监视之后,还需要再监视,就需要再一次调用watch key
命令
unwatch在事务中使用没意义,因为只要监视了并开启事务,只要其他客户端修改了,就不能执行事务,即使在事务中取消监视也不行。
九、配置文件 redis.conf
1、单位的装换关系
2、包含其他配置文件(INCLUDES)
3、网络配置(NETWORK)
bind 127.0.0.1 -::1
bind:代表监听的地址。默认情况下,如果没有指定“bind”配置指令,Redis会监听来自主机上所有可用网络接口的连接。绑定配置指令,后面跟着一个或多个IP地址,每个地址可以加前缀“-”,这意味着如果地址不可用,redis总是会被悄悄地跳过该地址。
protected-mode yes
保护模式是否开启
port 6379
端口
4、通用配置(GENERAL)
daemonize no
守护进程开启,默认为no,但我们一般改为yes,以后台的方式运行,否则启动redis后会占用终端
pidfile /var/run/redis_6379.pid
如果以后台的方式运行,就需要制定一个pid文件
loglevel notice
日志级别,分为debug调试、verbose详细、notice注意、warning警告
logfile “”
日志文件名。为空代表标准的输入输出
databases 16
数据库个数,默认16个
always-show-logo no
是否显示logo标志
5、快照(SNAPSHOTTING)重点
持久化使用的,该项设置规定的时间内,执行了n个操作之后,就会持久化到文件中
格式为:save seconds changes,redis默认自动任意时刻保存,但是我们可以修改。
stop-writes-on-bgsave-error yes
持久化失败之后是否继续工作
rdbcompression yes
是否开启压缩RDB文件,压缩意味着消耗CPU资源
rdbchecksum yes
是否开启RDB文件的自动校验,若发现错误就可以自动更正
dbfilename dump.rdb
dump数据库的文件名
dir ./
RDB数据文件保存的目录,在哪里启动redis服务,就保存在哪个目录下
6、主从复制(REPLICATION)
# replicaof <masterip> <masterport>
作为从节点时,设置主节点的IP和端口
7、安全(SECURITY)
# requirepass foobared
密码,默认注释掉,空密码
8、客户端(CLIENTS)
# maxclients 10000
设置连接redis的最大客户端的数量
9、内存管理(MEMORY MANAGEMENT)
# maxmemory
设置内存的最大使用值
# maxmemory-policy noeviction
内存到达最大值时的策略。有六种策略
-
volatile-lru: 只对设置了过期时间的key进行LRU(默认值)
-
allkeys-lru: 删除lru算法的key
-
volatile-random: 随机删除即将过期key
-
allkeys-random: 随机删除
-
volatile-ttl : 删除即将过期的
-
noeviction : 永不过期,返回错误
10、只附加模式(APPEND ONLY MODE)
也是持久化的一种方式,简称aof
appendonly no
默认不开启。默认使用rdb方式持久化,而不是aof方式
appendfilename “appendonly.aof”
持久化后的文件名字
# appendfsync always # 每次修改都同步一次,消耗性能
appendfsync everysec # 每秒同步一次,可能会丢失1秒的数据
# appendfsync no # 不同步
代表什么时候执行一次同步操作
十、持久化
RDB(Redis Database)
在指定的时间间隔内,将内存中的数据集快照写入磁盘,已达到持久化。恢复时将快照文件直接读到内存中。默认使用该模式进行持久化。
Redis会在主进程运行时,单独fork一个子进程来进行持久化操作,首先将数据写入到一个临时文件中,等持久化操作结束后,再将该临时文件替换上一次持久化好的RDB文件。
主进程没有参与文件I/O操作,这就确保了主进程能正常高性能工作。
对于大规模的数据恢复,且对数据恢复的完整性要求不高的,使用RDB方式更加高效。RDB的缺点就是最后一次持久化之后,由于断电等原因,内存中的新数据由于没有达到写入磁盘要求,就会丢失
默认文件名dump.rdb
关于RDB的配置,在配置文件redis.conf文件的快照项中修改,例如
# 10秒内发生5次修改操作就进行一次持久化操作。save 10 5
触发机制
- 满足save的规则
- 执行flushall命令,删除所有数据库的数据
- 退出redis,shutdown命令
恢复数据
启动redis之后,会根据配置文件,查看是否使用RDB的方式,查看RDB文件名,查看RDB文件保存位置,最后读取RBD文件的内容导入内存。因此,我们只需要根据配置文件的配置,把RDB文件放置到对应的目录下即可
修复dump.rdb文件
安装目录下有个redis-check-rdb工具,可以使用该工具对dump.rdb文件扫描修复,并不是完全修复正确,一般会删除出错的位置
AOF(Append Only File)
将我们操作的所有命令记录下来,需要恢复时,只需再执行一次所有命令。
Redis的主进程会fork一个子进程,有子进程以日志的形式记录每个写操作,不记录读操作,只能追加文件,不能修改文件。
恢复的时候,读取该命令文件中所有命令然后从头开始执行。这样的话就会消耗大量的计算资源
默认文件名appendonly.aof
默认不开启aof模式,我们需要手动开启
# 配置文件开启appendonly yes
# redis-cli命令行开启127.0.0.1:6379> config get appendonly1) "appendonly"2) "no"127.0.0.1:6379> config set appendonly yesOK127.0.0.1:6379> config get appendonly1) "appendonly"2) "yes"
开启之后就会自动在启动redis服务操作的目录下生成appendonly.aof
文件。
然后set age 18
操作,看看里面的内容
REDIS0009� redis-ver6.2.3�
�edis-bits�@�ctime2�`used-mem��N
aof-preamble���namexiaoout�:money���VFq�0�v*2
$6
SELECT
$1
0
*3
$3
set
$3
age
$2
18
修复appendonly.aof文件
安装目录下有个redis-check-aof工具,可以使用该工具对appendonly.aof文件扫描修复,并不是完全修复正确,一般会删除出错的位置
redis-check-aof --fix appendonly.aof
十一、发布订阅
订阅多个频道
subscribe
channel [channel …]
将信息发送到指定的频道
publish
channel message
取消频道的订阅
unsubscribe
[channel [channel …]]