Redis学习总结(Docker搭建环境)

中文版命令学习地址(有些参数没细讲):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进程查看工具,因此我们在主机下面查看
xxx

我一定要在容器中查看怎么办,可以,在redis容器中安装ps工具

root@b4a21afd7dc8:/data# apt install -y procps

3.基本使用

set key value,用于设置字符串类型的键值对

get key,用于获取某个键的值

keys pattern,pattern是正则表达式,用于获取某些键

xxx

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],关闭时可以选择是否保存本次操作的数据

sss

正常主机编译安装的redis,若是关闭redis服务,执行shutdown命令后,只会显示not connected

注意,使用Docker的方式运行Redis服务,若是关闭服务,就会自动关闭并退出容器

再次启动redis容器

xxx

启动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-k1=keep alive 0=reconnect1
8-rSET/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请求为例

xxx

四、Redis的基本概念

默认有16个数据库,在redis.conf文件大概在327行有记录databases 16,可以修改。默认使用的是0数据库

默认6379端口,大概在98行port 6379,可以修改。

单线程运行。数据都是在内存中操作,不会发生磁盘的I/O操作,相比之下多线程切换的时间更长

1.切换数据库

select index

xxx

2.查看数据库容量

dbsize

xxx

3.删除当前所选数据库的所有键

flushdb [ASYNC|SYNC]

  • ASYNC:异步刷新数据库
  • SYNC:同步刷新数据库

xxx

flushall [ASYNC|SYNC],删除所有数据库的键

五、5种基本数据类型

一)辅助命令

1、判断某个键是否存在

exists key [key …]

xxx

可以接多个键,存在多少个结果就是多少个

2、移动键到其他数据库

move key dbIndex

从当前数据库移动某个键到某一个数据库,如果目标数据库已存在或者源数据库不存在,则不操作。返回值为1则成功,为0则失败。

xxx

3、设置键的过期时间

expire key seconds

xxx

4、查看键的剩余存活时间

ttl key

xxx

5、查看键的类型

type key

127.0.0.1:6379> set name zhongOK127.0.0.1:6379> type namestring

二)string(字符串)

1、字符串拼接

append key value

在尾部追加字符串,并返回新字符串的长度。如果该键不存在,就创建该键,值为空字符串,然后再执行追加操作

xxx

2、获取字符串的长度

strlen key

127.0.0.1:6379> strlen say(integer) 10127.0.0.1:6379> get say"helloworld"
3、字符串类似数字般+1操作

incr key

xxx

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

xxx

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格式类型,如果使用字符串类型,那怎么设计

  1. 在服务端序列化成字符串之后保存,客户端拿到数据之后再进行反序列化

set user:1 {name:zhong,age:18}

  1. 把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的值,就会导致该事务执行失败

下面模拟该行为

  1. 在一个客户端中监视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命令提交执行
  1. 开启另一个客户端,修改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
  1. 此时第一步中的监视器已经发现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、单位的装换关系

xxx

2、包含其他配置文件(INCLUDES)

[xxx

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默认自动任意时刻保存,但是我们可以修改。

xxx

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

xxx

取消频道的订阅

unsubscribe [channel [channel …]]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值