Redis使用
一、redis安装
使用docker安装时遇到的问题
使用docker安装时遇到的问题以及解决办法
今天启动redis突然出现连接端口有问题,错误如下:
truedei@truedei:~$
truedei@truedei:~$ sudo docker start redis
Error response from daemon: driver failed programming external connectivity on endpoint redis (87977922525bd67cb6e39c26b2f0229081ff428693991d923c595752a733d41b): Error starting userland proxy: listen tcp 0.0.0.0:6379: bind: address already in use
Error: failed to start containers: redis
truedei@truedei:~$
就查了下端口,果然有在使用的:
truedei@truedei:~$ netstat -ntpl |grep 6379
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN -
truedei@truedei:~$
查一下是谁在占用,让我很是惊讶,居然是他自己,端口被占用了,而且还没启动
truedei@truedei:~$ ps -aux |grep 6379
redis 1397 0.0 0.0 42608 2292 ? Ssl 07:30 0:00 /usr/bin/redis-server 127.0.0.1:6379
truedei 5096 0.0 0.0 14536 976 pts/4 S+ 07:33 0:00 grep 6379
truedei@truedei:~$
truedei@truedei:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
truedei@truedei:~$
truedei@truedei:~$
先结束掉在说,奇怪的是,杀都杀不掉
truedei@truedei:~$ sudo kill -9 1397
truedei@truedei:~$ ps -aux |grep 6379
redis 8263 0.0 0.0 42608 2164 ? Ssl 07:35 0:00 /usr/bin/redis-server 127.0.0.1:6379
truedei 8291 0.0 0.0 14536 984 pts/4 S+ 07:35 0:00 grep 6379
truedei@truedei:~$
仔细看了一下这个redis并不是docker中安装的redis,而是在本机的:
/usr/bin/redis-server
那就停止掉本机的,果然可以了:
truedei@truedei:~$ /etc/init.d/redis-server stop
[ ok ] Stopping redis-server (via systemctl): redis-server.service.
truedei@truedei:~$
truedei@truedei:~$ ps -aux |grep 6379
truedei 10583 0.0 0.0 14536 948 pts/4 S+ 07:37 0:00 grep 6379
truedei@truedei:~$
truedei@truedei:~$
然后再启动:
truedei@truedei:~$
truedei@truedei:~$ sudo docker start redis
redis
truedei@truedei:~$
truedei@truedei:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
85cb7d83a2ff redis "docker-entrypoint.s…" 22 hours ago Up 5 seconds 0.0.0.0:6379->6379/tcp redis
truedei@truedei:~$
truedei@truedei:~$
解决docker中redis警告The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128
说个题外话,如果想要子在创建容器后执行多条命令,可以使用 sh -c “命令1 && 命令2 && 命令3” 这种模式
例如:这个是我尝试在容器启动时修改参数,但是失败了
docker run -p 6388:6379 --name redis6388 --sysctl net.core.somaxconn=1024 \
-v /mnt/docker/redis6388/data:/data \
-v /mnt/docker/redis6388/conf/redis.conf:/usr/local/etc/redis/redis.conf \
-d --restart=always redis \
sh -c "redis-server /usr/local/etc/redis/redis.conf --appendonly yes && sudo echo 511 > /proc/sys/net/core/somaxconn"
终极解决方案
首先查看docker run --help 中是否有 –sysctl 这个参数,如果有的话,可以使用下述命令解决此警告,命令如下:
docker run -p 6399:6379 --name redis6399 --sysctl net.core.somaxconn=1024 \
-v /mnt/docker/redis6399/data:/data \
-v /mnt/docker/redis6399/conf/redis.conf:/usr/local/etc/redis/redis.conf \
-v /proc/sys/net/core/somaxconn:/proc/sys/net/core/somaxconn \
-e TIME_ZONE="Asia/Shanghai" -e TZ="Asia/Shanghai" \
-d --restart=always redis redis-server /usr/local/etc/redis/redis.conf \
--appendonly yes
重点在 –sysctl net.core.somaxconn=1024
这里,至此问题解决
附加送解决redis时区不同步问题:-e TIME_ZONE=“Asia/Shanghai” -e TZ=“Asia/Shanghai”
二、Redis使用教程
redis介绍
redis默认有16个数据库
默认使用的第一个数据库,可以使用select 进行切换数据库
127.0.0.1:6379> select 3 #切换数据库
OK
127.0.0.1:6379[3]> dbsize #查看库的大小
(integer) 0
不同的数据库可以存储不同的值
Redis是单线程的:
Redis是很快的,官方表示,Redis是基于内存操作,CPU不是Redis性能瓶颈,Redis的瓶颈是根据机器的内存和网络带宽,既然可以使用单线程来实现,就使用单线程了 !
核心: Redis 是将所有的数据全部放在内存中的,所以说使用单线程去操作效率就是最高的,多线程(CPU上下文会切换:耗时的操作!!!),对于内存系统来说,如果没有上下文切换效率就是最高的!多次读写都是在一个CPU上的,在内存情况下,这个就是最佳的方案!
Redis 是在内存中的数据结构存储系统,可以用作数据库、缓存和消息中间件MQ。它支持多种类型的
数据结构,如字符串 ( strings),散列(hashes ),列表(lists),集合( sets ),有序集合( sorted sets ) 与范围查询
bitmaps,hyperloglogs 和地理空间(geospatial) 索引半径查询。Redis 内置了 复制(replication ),LUA脚本(Lua
scripting ),LRU驱动事件(LRU eviction ),事务( transactions ) 和不同级别的 磁盘持久化 ( persistence) ,并通过 Redis哨兵( Sentinel) 和自动 分区( Cluster ) 提供高可用性( high availability )。
redis命令使用
进去redis 使用 redis-cli -p 6379
进行连接测试
string类
string类使用场景
- 计数器
- 统计过单位的数量
- 粉丝数
- 对象缓存存储
使用set进行设置值,使用get获取值,del
删除值
查看是否存在
使用keys * 查看全部键,keys name 查找这个键
127.0.0.1:6379> select 3
OK
127.0.0.1:6379[3]> get age
"188"
127.0.0.1:6379[3]> keys age
1) "age"
127.0.0.1:6379[3]> keys age1
(empty array)
查找以me结尾的键 keys *me
flushall
或者 flushdb
删除所有的键
flashdb
清除当前数据库
flashall
请求全部数据库
127.0.0.1:6379[3]> flushdb
OK
127.0.0.1:6379[3]> keys *
(empty array)
127.0.0.1:6379[3]> set name 123
OK
127.0.0.1:6379[3]> get name
"123"
127.0.0.1:6379[3]> flushall
OK
使用expire设置过期时间
127.0.0.1:6379> set name 11
OK
127.0.0.1:6379> expire name 30 #设置过期时间为30秒
(integer) 1
127.0.0.1:6379> ttl name
(integer) 25
比如单点登陆可以设置过期时间
使用ttl查询过期时间,使用expire设置过期时间,时间为-1是没设置过期时间,为-2说明为已经过期或者没有值了
查询key类型
127.0.0.1:6379> type name #查询key类型
string
使用incr
进行增量存贮或使用decr
进行递减
incrby和decrby进行批量增加 / 减少
127.0.0.1:6379> set views 0
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views
(integer) 1
127.0.0.1:6379> incr views
(integer) 2
127.0.0.1:6379> get views
"2"
127.0.0.1:6379> decr views
(integer) 1
127.0.0.1:6379> decr views
(integer) 0
127.0.0.1:6379> decr views
(integer) -1
127.0.0.1:6379> get views
"-1"
127.0.0.1:6379> get views
"-1"
127.0.0.1:6379> INCRBY views 10 #incrby批量增加
(integer) 9
127.0.0.1:6379> DECRBY views 5 #decrby批量减少
(integer) 4
获取指定字符串范围 getrange
127.0.0.1:6379> set strings abcdefghijklmn
OK
127.0.0.1:6379> getrange strings 0 3 #截取字符串指定长度
"abcd"
替换指定位置开始的字符串
127.0.0.1:6379> set key2 abcdefghijklmn
OK
127.0.0.1:6379> get key2
"abcdefghijklmn"
127.0.0.1:6379> setrange key2 1 xx # 替换为xx
(integer) 14
127.0.0.1:6379> get key2
"axxdefghijklmn"
setex (set with exprie) #设置过期时间
setnx (set if not exist) #不存在则设置 (在分布锁中经常使用)比如修改成功版本号加修改失败就不加1
127.0.0.1:6379> set name nbsb
OK
127.0.0.1:6379> setnx name 111
(integer) 0
127.0.0.1:6379> setex age 20 100 #设置age为100并20秒后过期
OK
127.0.0.1:6379> ttl age #查询过期时间,-2为过期,-1为永久
(integer) 17
127.0.0.1:6379> msetnx k1 v1 k4 v4 #msetnx 是原子性操作,要么一起成功要么一起失败
(integer) 0
使用mset批量设置key
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 #批量设置值
OK
127.0.0.1:6379> keys *
1) "k1"
2) "k3"
3) "k2"
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> mget k1 k2 k3 #批量获取值
1) "v1"
2) "v2"
3) "v3"
实战演示string
# 这里的key是一个巧妙的设计 : user:{id}:{filed}
# 设置user:1:name是键 ,张三是值 | user:1:age 是键 18是值
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 18
OK
127.0.0.1:6379> keys *
1) "user:1:name"
2) "user:1:age"
#存贮一个json字符串
127.0.0.1:6379> set user:2 {name:zhangsan,age:19}
OK
127.0.0.1:6379> get user:2
"{name:zhangsan,age:19}"
使用getset命令
先get在set
127.0.0.1:6379> getset db redis
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db docker
"redis"
127.0.0.1:6379> get db
"docker"
修改键的名称
127.0.0.1:6379> set name qwer
OK
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> rename name namess
OK
127.0.0.1:6379> keys *
1) "namess"
列表
在redis可以将list用成栈、队列、阻塞队列
消息队列(Lpush Rpop) 栈(Lpush Lpop)
使用lpush 添加列表,使用lrange查询列表
lpush是从左至右依次添加,所以是第一个在最下面
lrange查询列表的是查询从0到-1 ,-1表示是最后一个元素
使用rpush添加到尾部,使用lpsuh添加到头部(相当于双端队列,可以两边都可以插值)
使用lpop和rpop进行删除头部或者尾部
查询list元素
127.0.0.1:6379> lrange list 0 -1 #查询list
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lindex list 1 #使用指定索引查询
"two"
llen list1 #使用llen查询列表长度
ltrim list1 1 3 #修剪:删除1-3索引以外的元素
lrem list 1 one #移除指定个数的value,精确匹配
rpoplpush #移除列表最后一个元素,并将他移动到一个新的列表中
修改指定元素值
127.0.0.1:6379> lrange list 0 -1
1) "lll"
2) "three"
3) "one"
127.0.0.1:6379> lset list 0 element
OK
127.0.0.1:6379> lrange list 0 -1
1) "element"
2) "three"
3) "one"
在指定元素前/后插入
127.0.0.1:6379> rpush mylist hello
(integer) 1
127.0.0.1:6379> rpush mylist world
(integer) 2
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "world"
127.0.0.1:6379> LINSERT mylist before world other # 在这个元素之前插入
(integer) 3
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "other"
3) "world"
127.0.0.1:6379> LINSERT mylist after hello one # 在这个元素之后插入
(integer) 4
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "one"
3) "other"
4) "world"
集合
set是不能重复的集合,可以用于抽取随机
增加元素
sadd myset hello
查询元素
127.0.0.1:6379> sadd myset one two stree
#查询a是否在集合set1中
(integer) 3
127.0.0.1:6379> sismember myset one
(integer) 1
127.0.0.1:6379> sismember myset one2
(integer) 0
127.0.0.1:6379> SMEMBERS myset #查询所有元素
1) "stree"
2) "one"
3) "two"
删除元素
srem set1 a #删除里面元素
127.0.0.1:6379> SMEMBERS myset
1) "stree"
2) "one"
3) "two"
127.0.0.1:6379> spop myset #随机删除集合中的元素
"two"
127.0.0.1:6379> spop myset
"stree"
将指定元素移动到指定集合中
也可以类似于删除指定元素,将这个元素移动到另一个集合在将那个集合删除
SADD set1 "A"
SADD set1 "B"
SADD set1 "C"
SADD set2 "X"
SADD set2 "Y"
SMOVE set1 set2 "A"
交集、差集、并集
可以用于类似 b站共同关注
- 并集 sunion
- 交集 sinter (共同好友例子)
- 差集 sdiff
127.0.0.1:6379> sadd myset1 a b c d e
(integer) 5
127.0.0.1:6379> sadd myset2 a b f g h
(integer) 5
127.0.0.1:6379> SUNION myset1 myset2 #并集
1) "c"
2) "d"
3) "a"
4) "g"
5) "b"
6) "e"
7) "h"
8) "f"
127.0.0.1:6379> SINTER myset1 myset2 #交集
1) "a"
2) "b"
127.0.0.1:6379> sdiff myset1 myset2 #差集
1) "e"
2) "d"
3) "c"
获取元素数目
scard myset
随机获取指定数量成员
127.0.0.1:6379> SRANDMEMBER myset 2
1) "stree"
2) "two"
127.0.0.1:6379> SRANDMEMBER myset 2
1) "stree"
2) "two"
127.0.0.1:6379> srandmember myset #默认获取一个
"one"
有序集合
添加一个值和添加多个值
127.0.0.1:6379> zadd myset 1 one #前面必须加一个数字,可以理解为id,这个id可以是任意的,可以用于排名
(integer) 1
127.0.0.1:6379> zadd myset 2 two 3 three
(integer) 2
127.0.0.1:6379> zrange myset 0 -1
1) "one"
2) "two"
3) "three"
排序
127.0.0.1:6379> zadd salary 2500 xiaohong
(integer) 1
127.0.0.1:6379> zadd salary 5000 zhangsan
(integer) 1
127.0.0.1:6379> zadd salary 500 nbsb
(integer) 1
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf
1) "nbsb"
2) "xiaohong"
3) "zhangsan"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf withscores #获取全部参数并且有比分的参数
1) "nbsb"
2) "500"
3) "xiaohong"
4) "2500"
5) "zhangsan"
6) "5000"
127.0.0.1:6379> zrange salary 0 -1 withscores #获取有比分的参数
1) "nbsb"
2) "500"
3) "xiaohong"
4) "2500"
5) "zhangsan"
6) "5000"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf 2500 withscores #获取2500以内比分的升序参数
1) "nbsb"
2) "500"
3) "niuma"
4) "500"
5) "xiaohong"
6) "2500"
127.0.0.1:6379> ZREVRANGE salary 0 -1 #从大到小 降序排序
1) "zhangsan"
2) "xiaohong"
3) "niuma"
4) "nbsb"
127.0.0.1:6379> ZREVRANGE salary 0 -1 withscores #降序排序并且附带比分
1) "zhangsan"
2) "5000"
3) "xiaohong"
4) "2500"
5) "niuma"
6) "500"
7) "nbsb"
8) "500"
移除rem元素
zrem result qinghua #删除元素
获取集合中个数
127.0.0.1:6379> zcard salary #获取这个集合中的个数
(integer) 3
127.0.0.1:6379> zadd myset 1 nbsb 2 xrkx 3 macsb
(integer) 3
127.0.0.1:6379> zcard mysetr
(integer) 0
127.0.0.1:6379> zcard myset
(integer) 3
127.0.0.1:6379> zcount myset 0 1 #获取指定区间成员数量
(integer) 1
127.0.0.1:6379> zcount myset 0 2
(integer) 2
哈希Hash
Map集合 , key-map 这时候值是一个map集合,本质和string类型没有太大区别,还是简单的key-value
hash变更的数据 user name age,尤其是是用户信息之类的,经常变动的信息! hash 更适合于对象的存储,String更加适合字符串存储!
设置hash
127.0.0.1:6379> hset person name nbsb #设置
(integer) 1
127.0.0.1:6379> hget person name #获取
"nbsb"
127.0.0.1:6379> hmset person name1 zhangsan name2 lisi name3 niubi #批量设置
OK
127.0.0.1:6379> hmget person name1
1) "zhangsan"
127.0.0.1:6379> hmget person name1 name2 name3 # 批量获取
1) "zhangsan"
2) "lisi"
3) "niubi"
127.0.0.1:6379> hsetnx person name 11 #如果已经存在就不设置
(integer) 0 #已经存在设置失败
127.0.0.1:6379> hsetnx person name5 11
(integer) 1#设置成功
获取hash值
127.0.0.1:6379> hgetall person
1) "name"
2) "niubi"
3) "name1"
4) "zhangsan"
5) "name2"
6) "lisi"
7) "name3"
8) "niubi"
person中的对应的name是nbsb,age是100,都是成对出现的
只获取键或者值
127.0.0.1:6379> hkeys person
1) "name"
2) "name1"
3) "name2"
4) "name3"
127.0.0.1:6379> hvals person
1) "niubi"
2) "zhangsan"
3) "lisi"
4) "niubi"
递增方法 incr decr
hash中没有decr,但是incrby可以设置负值,上面的string中的incr也可以设置负值
127.0.0.1:6379> hset myhash field 0
(integer) 1
127.0.0.1:6379> HINCRBY myhash field 1
(integer) 1
127.0.0.1:6379> HINCRBY myhash field 2
(integer) 3
127.0.0.1:6379> HINCRBY myhash field -1
(integer) 2
127.0.0.1:6379> HINCRBY myhash field -2
(integer) 0
删除元素使用hdel
hdel person age
hexists person name #查寻person 中的 name 是否存在
hkeys person
hlen person
发布订阅模式
publish helloword nihao #向helloword进行发布订阅
subscribe helloword #接受helloword的订阅消息
订阅模式弊端,没法记录历史,消息不可持久化
使用xadd添加stream消息
xadd geenkhour * coures docekr # *代表自动生成id,这个消息idd必须是递增的
xadd geenkhour 1-1 coures docekr # 第一个整数表示时间戳,第二个整数表示序列号
xtrim geekhour maxlen 0 # 表示删除所有消息
geospatial添加地理位置
添加城市
127.0.0.1:6379> geoadd china:city 116 40 beijing
(integer) 1
127.0.0.1:6379> geoadd china:city 121 31 shanghai
(integer) 1
127.0.0.1:6379> geoadd china:city 120 30 hangzhou 108 34 xian
(integer) 2
获取城市经纬度
127.0.0.1:6379> geopos china:city xian
1) 1) "108.00000160932540894"
2) "34.00000062127011091"
获取两地距离
- m 表示米
- km千米
- mi 英里
- ft 英尺
127.0.0.1:6379> geodist china:city beijing shanghai #查询两地直线举例
"1098158.0237"
127.0.0.1:6379> geodist china:city beijing shanghai km
"1098.1580"
127.0.0.1:6379> georadius china:city 110 30 1100 km
#查询离这个经纬度方圆1100千米内的城市
1) "xian"
2) "hangzhou"
3) "shanghai"
127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 2000 km #指定查询位置
1) "xian"
2) "hangzhou"
3) "shanghai"
4) "beijing"
测试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*(L 的小写字母) | 生成循环,永久执行测试 | |
13 | -t | 仅运行以逗号分隔的测试命令列表。 | |
14 | *-I*(i 的大写字母) | Idle 模式。仅打开 N 个 idle 连接并等待。 |
测试100并发连接 100000请求
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
我这里是在 redis/src下测试的,因为redis-benchmark在这个文件下
100 parallel clients
是100个并发客户端
3 bytes payload
是每次只写入3个字节
keep alive
每次只有一个服务器连接
版权属于:戏人看戏博客网
本文链接:https://day.nb.sb/archives/1214.html
若无注明均为戏人看戏原创,转载请注明出处,感谢您的支持!