redis
搭建
下载redis.conf
http://download.redis.io/redis-stable/redis.conf
http://download.redis.io/redis-stable/sentinel.conf
部署容器
docker run --restart=always --log-opt max-size=100m --log-opt max-file=2 -p 6379:6379 --name redis -v /home/redis/redis.conf:/etc/redis/redis.conf -v /home/redis/data:/data -d redis redis-server /etc/redis/redis.conf --appendonly yes --requirepass 密码
进入容器
docker exec -it redis /bin/bash
redis-cli
auth default 密码
连接
默认用户名:default
密码:密码
创建用户
acl setuser lhc on >密码
连接redis
const { createClient } = require('redis');
const client = createClient({
url: 'redis://default:密码@ip:port'
})
const createLimit = async () => {
await client.connect()
await client.set('key', 'value')
const value = await client.get('key')
console.log(value)
await client.disconnect();
}
createLimit().then()
切换数据库
await client.select(db)
Redis内置方法
String
await client.set(key, value)
await client.get(key)
await client.mSet([key1,value1,key2,value2])
await client.mGet([key1,key2])
await client.expire(key, 10) 设置key的过期时间,单位s
await client.setEx(key,30,value) 设置key的过期时间,单位s
await client.ttl(key) 获取当前key的过期时间,-1代表永不过期
await client.setNX(key,value) 如果key不存在就设置,存在就不操作
await client.keys('*') 获取全部key
await client.exists(key) 判断key是否存在
await client.type(key) 查看当前key的类型
await client.append(key,value) 往某个key的value追加值
await client.strLen(key) 获取key的长度
await client.incr(key) 当前key值+1
await client.decr(key) 当前key值-1
await client.incrBy(key,10) 当前key值+10
await client.decrBy(key,10) 当前key值-10
await client.getRange(key,start,end) 截取当前字符串的值,区间为[start,end],-1代表最后一位
await client.setRange(key,start,replace_value) 替换指定范围的值
List
await client.lPush(key,value) 往队列的前面追加数据,value = string || array
await client.rPush(key,value) 往队列的后面追加数据,value = string || array
await client.lRange(key,start,end) 截取当前list的值,区间为[start,end],-1代表最后一位
await client.lPop(key) 移除list的第一个元素
await client.rPop(key) 移除list的最后一个元素
await client.lIndex(key,index) 获取list指定的index的值
await client.lLen(key) 获取list的长度
await client.lRem(key,count,value) 移除list中的value,移除的个数为count
await client.lTrim(key,start,end) 修改list,取区间索引为[start,end]的值
await client.rPopLPush(list1,list2) 移除list1的最后一个元素并插入到list2的前面追加数据
await client.lSet(key,index,value) list[index] = value
await client.lInsert(key,'BEFORE',value,insrt_value)往list里面value之前插入insrt_value,只插入一个值
Set
await client.sAdd(key,value) value = string || array
await client.sMembers(key) 获取key的所有值
await client.sIsMember(key,value) 判断value是否在当前key中
await client.sCard(key) 获取key的长度
await client.sRem(key,value) 移除某个元素
await client.sRandMemberCount(key,count) 获取随机count个元素
await client.sPop(key) 删除一个随机元素
await client.sMove(key1,key2,value) 从key1中删除value,并插入到key2中
await client.sDiff([key1,key2]) 获取key1与key2的差集
await client.sInter([key1,key2]) 获取key1与key2的交集
await client.sUnion([key1,key2]) 获取key1与key2的并集
Hash
await client.hSet(hash_name,key,value) 设置单个hash值
await client.hSet(hash_name,[key,value,key1,value1])设置多个hash值
await client.hGet(hash_name,key) 获取单个hash值
await client.hmGet(hash_name,[key1,key2]) 获取多个hash值
await client.hGetAll(hash_name) 获取全部hash值
await client.hDel(hash_name,key) 删除单个hash值
await client.hLen(hash_name) 获取hash字段长度
await client.hExists(hash_name,key) 判断key是否存在
await client.hKeys(hash_name) 获取全部的key
await client.hVals(hash_name) 获取全部的values
await client.hIncrBy(hash_name,key,count) key值+count
await client.hSetNX(hash_name,key,value) 如果key不存在就设置,存在就不操作
Zset
min_value = '-inf'
max_value = '+inf'
await client.zAdd(key,[{score, value}]) 创建
await client.zRangeByScore(key,min_value,max_value) 对score进行排序,返回key
await client.zRangeByScoreWithScores(key,min_value,max_value) 对score进行排序,返回[{score, value}]
await client.zRange(key,start,end) 截取指定区间的值,返回[{score, value}]
await client.zRangeByScore(key,min_value,max_value) 获取指定区间的score的key
await client.zCard(key) 获取score数量
await client.zCount(key,min_value,max_value) 获取指定区间的score的数量
await client.zRem(key,value) 移除指定value
Geo
await client.geoAdd(key,[{longitude:经度, latitude:纬度, member:city}])
await client.geoDist(key,city1,city2,'km') 获取两地直线距离
await client.geoRadius(key,{longitude:经度, latitude:纬度},10000,'km') 获取当前经纬度1000km内的数据
Hyperloglog
await client.pfAdd(key,[value1,value2]) 创建
await client.pfCount(key) 统计数量
await client.pfMerge(key,key1,key2) key1,key2合并生成key
Bitmap
await client.setBit(key,number,0|1) 创建
await client.getBit(key,number) 获取
await client.bitCount(key) 统计为1的数量
事务
await client.multi().set(key,value).get(key,value).exec() 开启事务
await client.multi().set(key,value).get(key,value).discard() 取消事务
乐观锁
await client.multi()
.watch(value) value = string | array
.set(key,value)
.get(key,value)
.exec()
await client.multi()
.watch('count')
.set('count',1000)
.exec()
如果在开启事务之后,执行exec函数之前有人修改了count字段的值,exec将不会执行
redis.conf
bind 127.0.0.1 -::1 绑定的ip
protected-mode yes 保护模式
port 6379 绑定的端口
daemonize yes 以守护进程的方式运行,默认是no,需要开启为yes
loglevel notice 日志的级别
logfile "" 日志的文件位置
databases 16 数据库数量
always-show-logo no 是否展示logo
stop-writes-on-bgsave-error yes 持久化工作如果出错,是否要继续工作
rdbcompression yes 是否压缩rdb文件,这个过程需要消耗cpu资源
rdbchecksum yes 保存rdb文件时,进行错误的检查校验
dir ./ rdb保存的目录
requirepass 密码 设置密码,默认是空,可配置
maxclients 10000 连接客户端的最大数量,默认是空,可配置
maxmemory-policy noeviction 内存达到最大限制时的策略
appendonly no 默认不开启aof模式,默认使用rdb
appendfilename "appendonly.aof" 持久化的文件的名称
appendfsync everysec 每秒执行一次sync,可能会丢失这一秒的数据
持久化
rdb
触发rdb规则的情况:
1.save规则满足的情况下
2.执行flushAll
3.退出redis
优点:
1.适合大规模的数据护恢复
2.对数据的完整性要求不高
缺点:
1.需要一定的时间间隔进程操作,如果redis意外宕机,最后一次的数据可能会丢失
2.fork进程时会占用一定的内存空间
aof
将我们的命令全部记录起来,history,恢复的时候全部执行一遍
优点:
1.每次修改都同步,文件的完整性会更加好
2.每秒同步一次,可能会丢失一秒的数据
3.从不同步,效率最高
缺点:
1.相对于数据文件来说,aof远远大于rdb,修复的时候也比rdb慢
2.aof的运行效率也要比rdb慢,
发布订阅
const sub = createClient({
url: 'redis://default:密码@ip:port'
})
const pub = createClient({
url: 'redis://default:密码@ip:port'
})
const publish = async () => {
await pub.connect()
for (let i = 0; i < 5; i++) {
await pub.publish('list',`test${i}`)
}
await pub.disconnect();
}
const subscribe = async () =>{
await sub.connect()
await sub.subscribe('list',(data)=>{
console.log(data)
})
}
主从复制
作用:
1.数据冗余
2.故障恢复
3.负载均衡
4.高可用
主节点负责写,从节点负责读
复制原理
从节点不在线,重新连接到master节点的话,是全量复制
从节点在线,master节点是增量复制
部署
部署主节点
docker run --restart=always --log-opt max-size=100m --log-opt max-file=2 -p 6379:6379 --name redis -v /home/redis/master/redis.conf:/etc/redis/redis.conf -v /home/redis/master/data:/data -d redis redis-server /etc/redis/redis.conf --appendonly yes --requirepass 密码
部署从节点
docker run --restart=always --log-opt max-size=100m --log-opt max-file=2 -p 6380:6380 --name redis1 -v /home/redis/slave1/redis.conf:/etc/redis/redis.conf -v /home/redis/slave1/data:/data -d redis redis-server /etc/redis/redis.conf --appendonly yes --requirepass 密码
docker run --restart=always --log-opt max-size=100m --log-opt max-file=2 -p 6381:6381 --name redis2 -v /home/redis/slave2/redis.conf:/etc/redis/redis.conf -v /home/redis/slave2/data:/data -d redis redis-server /etc/redis/redis.conf --appendonly yes --requirepass 密码
配置从节点
通过命令配置
非永久
进入redis1容器
docker exec -it redis1 /bin/bash
redis-cli
auth default 密码
slaveof 主节点ip 主节点端口
进入redis1容器
docker exec -it redis2 /bin/bash
redis-cli
auth default 密码
slaveof 主节点ip 主节点端口
通过redis.conf配置
永久(建议)
slave1的redis.conf
replicaof 主节点ip 主节点端口
masterauth 主节点密码
masteruser 主节点账号
slave2的redis.conf
replicaof 主节点ip 主节点端口
masterauth 主节点密码
masteruser 主节点账号
哨兵模式
配置redis.conf
基于该文件去修改一些参数: http://download.redis.io/redis-stable/redis.conf
部署主节点
主redis.conf
port 6379
bind 127.0.0.1 -::1(注释掉)
docker run --restart=always --log-opt max-size=100m --log-opt max-file=2 -p 6379:6379 --name redis -v /home/redis/master/redis.conf:/etc/redis/redis.conf -v /home/redis/master/data:/data -d redis redis-server /etc/redis/redis.conf --appendonly yes --requirepass 密码
部署从节点
slave1的redis.conf
port 6380
bind 127.0.0.1 -::1(注释掉)
replicaof 主节点ip 主节点端口
masterauth 主节点密码
masteruser 主节点账号
docker run --restart=always --log-opt max-size=100m --log-opt max-file=2 -p 6380:6380 --name redis1 -v /home/redis/slave1/redis.conf:/etc/redis/redis.conf -v /home/redis/slave1/data:/data -d redis redis-server /etc/redis/redis.conf --appendonly yes --requirepass 密码
slave2的redis.conf
port 6381
bind 127.0.0.1 -::1(注释掉)
replicaof 主节点ip 主节点端口
masterauth 主节点密码
masteruser 主节点账号
docker run --restart=always --log-opt max-size=100m --log-opt max-file=2 -p 6381:6381 --name redis2 -v /home/redis/slave2/redis.conf:/etc/redis/redis.conf -v /home/redis/slave2/data:/data -d redis redis-server /etc/redis/redis.conf --appendonly yes --requirepass 密码
配置sentinel.conf
基于该文件去修改一些参数: http://download.redis.io/redis-stable/sentinel.conf
主节点的sentinel.conf
port 26379
sentinel announce-ip 服务器ip
sentinel announce-port 8879
sentinel monitor mymaster 服务器ip 6379 1
sentinel auth-pass mymaster 主节点redis密码
sentinel auth-user mymaster 主节点redis账号(默认default)
requirepass 当前redis节点密码
docker run -it --name sentinel1 -p 8879:26379 -v /home/redis/master/sentinel.conf:/etc/redis/sentinel.conf -d redis redis-sentinel /etc/redis/sentinel.conf
slave1的sentinel.conf
port 26380
sentinel announce-ip 服务器ip
sentinel announce-port 8880
sentinel monitor mymaster 服务器ip 6379 1
sentinel auth-pass mymaster 主节点redis密码
sentinel auth-user mymaster 主节点redis账号(默认default)
requirepass 当前redis节点密码
docker run -it --name sentinel2 -p 8880:26380 -v /home/redis/slave1/sentinel.conf:/etc/redis/sentinel.conf -d redis redis-sentinel /etc/redis/sentinel.conf
slave2的sentinel.conf
port 26381
sentinel announce-ip 服务器ip
sentinel announce-port 8881
sentinel monitor mymaster 服务器ip 6379 1
sentinel auth-pass mymaster 主节点redis密码
sentinel auth-user mymaster 主节点redis账号(默认default)
requirepass 当前redis节点密码
docker run -it --name sentinel3 -p 8881:26381 -v /home/redis/slave2/sentinel.conf:/etc/redis/sentinel.conf -d redis redis-sentinel /etc/redis/sentinel.conf
连接哨兵
const Redis = require('ioredis');
const redis = new Redis(
{
username:redis账号,
password:redis密码,
name: 哨兵名称,
sentinelUsername:哨兵账号,
sentinelPassword:哨兵密码,
sentinels: [
{
host: 哨兵1ip,
port: 哨兵1端口
},
{
host: 哨兵2ip,
port: 哨兵2端口
},
{
host: 哨兵3ip,
port: 哨兵3端口
},
]
}
);
redis.set('node-sentinel', 'test9999');