Redis介绍
- DB缓存、减少服务器压力
- 提高系统响应时间(响应时间、延迟时间、吞吐量、并发用户量、资源利用率)
- 做 Seccion 分离 (登陆信息)
- 做分布式锁 (Redis)
- 做乐观锁(Redis):任务队列(秒杀、抢红包等)
- 冷热数据交换
- 签到 bitmap
- 应用排行榜 zset
优势
- 提升用户体验
- 减少服务器压力
- 提升系统性能
代价
- 额外的硬件支出
- 高并发缓存失效
- 缓存与数据库数据同步
- 缓存并发竞争
- Cache Aside Pattern(旁路缓存): 先读缓存、在读数据库,然后取出数据后放入缓存,同时返回响应
- Read/Write Through Pattern : 应用程序只操作缓存,缓存操作数据库
- Write Behind Caching Pattern : 应用程序只更新缓存
- 先更新数据库,再更新缓存 :update与commit之间,更新缓存,commit失败,则DB与缓存数据不一致
- 先删除缓存,再更新数据库 :update与commit之间,有新的读,缓存空,读DB数据到缓存 数据是旧的数据,commit后 DB为新数据,则DB与缓存数据不一致
- 先更新数据库,再删除缓存(推荐):update与commit之间,有新的读,缓存空,读DB数据到缓存 数据是旧的数据,commit后 DB为新数据,则DB与缓存数据不一致,采用延时双删策略
数据库启动
# 服务端启动
redis-server.exe
./redis-server redis.conf
# 客户端启动、并连接服务端
# -h :redis 服务器的IP地址
# -p : redis实例的端口号
./redis-cli -h 127.0.0.1 -p 6379 # 默认值
# 后端服务关闭
./redis-cli shutdown
"""
redis-server :启动redis 服务
redis-cli :进入redis 命令客户端
redis-benchmark : 性能测试的工具
redis-check-aof : aof 文件进行检查的工具
redis-check-dump : rdb 文件进行检查的工具
redis-sentinel : 启动哨兵监控服务
"""
DBSIZE # 查看当前数据库的key数量
get keys * # 查看key的内容
FLUHSDB # 清空当前数据库key的数量
FLUSHALL # 清空所有库的key
exists key # 判断key是否存在
Redis配置文件
https://www.cnblogs.com/kreo/p/4423362.html # 配置详解
https://www.cnblogs.com/kreo/p/4423362.html # 配置详解
bind 127.0.0.1 # 默认绑定地址(只允许本机访问)
bind 0.0.0.0 # 允许所有的地址进行连接
port 6379 # redis 服务端口
save th DB on disk: # 将数据存储到硬盘
save 900 1 # 900 内至少有一个数据发生了变化 即保存
save 300 10
save 60 10000
daemonize no/yes # 设置是否后台运行
键-值
set # 设置值 set name lcl
get # 获取值 get name
mset # 设置多个值 mset name lcl age 18 sex 1
mget # 添加多个值 mget name age sex
append # 添加字段 append name 2 —— lcl2
del # 删除 del name
strlen # 返回字符串长度 strlen age
expire # 设置过期时间 expire name 3
setex name 3 lcl # = set name lcl + expire name 3
# 字符串计数功能
incr # 增加 incr num 每次点击增加 1 ,用于库存,描述等
decr # 减少
incrby # 指定增加多少 incrby nnum 2 指定num 加 2
decrby # 指定减少多少
getrange # 获取指定区间范围内的值(类似 between...and) getrange name 0 4 获取name字符串的0-4位
setrange # 代表从第几位位开始替换,下脚本从零开始 setrange name 5 456 从第五位开始替换
# (0 -1 表示全部)
redis-list(单值多value)
- List 是简单的字符串表,按照插入顺序排序,可以添加一个元素的头部(左边)或者尾部(右边),底层实际是一个链表
lpush/rpush/lrange # 从左/从右/获取指定长度
lpush list01 1 2 3 4 5 # list01从左侧添加 1 2 3 4 5(添加后为倒序)
rpush list02 1 2 3 4 5 # list01从右侧添加 1 2 3 4 5(添加后为正序)
lrange list01 0 -1 # 获取list01中所有的值
lpop/rpop # 移除最左/最右(从左侧移除、从右侧移除)
lpop list01 # 从左侧移除 例如(1 2 3 4 5) 移除元素5
rpop list01 # 从左侧移除 例如(1 2 3 4 5) 移除元素1
lrange list01 0 -1 # 获取list01中所有的值
lindex list01 1 # 按照索引下标获取元素(list01表中 按照下标1 获取元素)
llen list01 # 求列表长度
lrem list01 2 1 # 在list01中删除2个1
ltrim "开始index" "结束index" # 截取指定范围的值后在赋值给key
ltrim list01 0 2 # 截取list01 从 0 到 2 的数据在赋值给list01
rpoplpush list1 list2 # 将list01中最后一个压入list2中第一位
lrange list01 0 -1
lrange list02 0 -1
rpoplpush list1 list2
lset list02 0 X # 将list02 中第一位换成X
linsert key before/after
linsert list01 before x php # 在 list01 中 在 X 之前加字段php
Redis- Hash数据类型
hset user id 11 # 设值 user {id : 11} 内部无冒号
hget user id # 取值 返回 11
hmset user id 12 name lcl sex man # 向user 中插入 id 、name 、sex 键值对
hmget user id name sex # 获取 id、name、sex 的值
hgetall user # 获取 user 中的所有键值
hdel user id # 删除 user 中 id 的键值对
de user # 删除 user
hlen user # 求 user 长度 user {id : 11}
hexistes "key" # 在key里面某个值存在返回 1,不存在返回 0
hkeys users # 列举users 里面的key
hvals users # 列举users 里面的value
redis-set(集合)
sadd set01 1 2 3 4 2 3 4 # 去重添加集合元素 (1 2 3 4)
smembers set01 # 列举set01 中的元素
sismember set01 1 # 判断元素是否存在,如果存在返回1,不存在返回0
scard # 获取集合里面的元素个数
scard set01
srem key value
srem # 删除集合中元素
srem set01 3 # 删除set01 中的 3
smembers set01 # 查看集合
srandmember key + "数字个数"# 随机取几个数
srandmember set02 2 # 在set02 中随机取2个数
spop key # 随机弹出
spop set01 # set01 中随机弹出1个数(删除了)
smove key1 key2
sadd set01 set03 2 # 将set01中的2 移动到set03中
SDIFF set01 set02 # 两个集合的差集
SINTER set01 set02 # 交集
SUNION set01 set02 # 并集 返回set01 set02 中的值,去掉重复
redis-Zset(有序集合)
# 添加数据 —— 进入集合后 会按照键的大小进行排序(默认升序)
zadd zset01 60 v1 70 v2 80 v3 90 v4 100 v5
zrange zset01 0 -1 # 查看所有值
zrange zset01 0 -1 withscores # 取所有的内容
zrangebyscore key start end # ----根据开始结束来取值
zrangebyscore zset01 60 70 # 取 60 -70 之间值
zrangebyscore zset01 60 (90 # 表示不包含90
zrangebyscore zset01 60 90 limit 1 2 # 从第一条开始截取2条,用于翻页
zrem key value # 某score下对应的value值,作用是删除元素
zrem zset01 v1 # 根据值来做删除
zcard zset01 # 求zset01 总条数
zcount zset01 60 90 # 求氛围在 60-90 的个数
zrank zset01 v2 # 返回1 返回对应下角标,从0开始
Redis 的python客户端
pip install redis # 安装
# 通过python连接Redis (两种写法)
r = redis.StrictRedis(host ="localhost",port=6379,db =0)
r = redis.Redis(host ="localhost",port=6379,db =0)
import redis
class RedisString(object):
def __init__(self):
# 写法 1
self.r = redis.StrictRedis(host ="localhost",port=6379,db =0)
# 写法 2
self.r = redis.Redis(host ="localhost",port=6379,db =0)
def string_set(self,skey,svalue):
res = self.r.set(skey,svalue)
print(res) # 返回true /fa
return res
def main():
r = RedisString()
r.string_set("user","lcl")
if __name__ == '__main__':
main()
** Redis 的 java客户端 - Jedis**
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
@Test
public void testConn(){
//与Redis建立连接 IP+port
Jedis redis = new Jedis("192.168.127.128", 6379);
//在Redis中写字符串 key value
redis.set("jedis:name:1","jd-zhangfei");
//获得Redis中字符串的值
System.out.println(redis.get("jedis:name:1"));
//在Redis中写list
redis.lpush("jedis:list:1","1","2","3","4","5");
//获得list的长度
System.out.println(redis.llen("jedis:list:1"));
}
** Redis性能说明 **
- 读 : 110000 次/s
- 写 :81000 次/s
- 长期使用,key会不断增加,Redis作为缓存使用,物理内存也会满
- 内存与硬盘交换(swap) 虚拟内存 ,频繁IO 性能急剧下降
** Redis过期策略说明 **
- maxmemory : 设置最大使用内存
- expire : 对数据设置过期时间
- 删除策略
- 定时删除 : 设置键的时候,同时设置定时器,到期立即执行
- 惰性删除 :key被访问时,如果发现失效,则删除键值
- 主动删除,
- 默认 : 不删除 : maxmemory-policy allkeys-lru
- LRU (Least recently used) : 最近最少使用淘汰
- LFU (Least frequently used) : 最近一段时间内使用量少则淘汰
- 较好方案 :惰性删除 + 主动删除
- 主数据库(master)—— 数据写入
- 从数据库(slave)—— 数据库的读取
- 通过配置主从数据库实现数据库的读写分离 ( 网站的读写比例一般位10 :1)
- master 和 slave 都是一个redis实例
bin 0.0.0.0 # 或者修改成本机IP
src / redis-server redis.conf
- 为从机服务配置文件 — 复制 etc / redis / redis.conf 文件
cp redis.conf slave.conf
- 修改 redis / save.conf 文件
vim slave.conf
bind 192.168.154.131 # 从机绑定主机IP
port 6378 # 修改当前服务器的服务端口
# 设置当前服务器的复制设置(linux)
replicaof <masterip><masterport>
replicaof 192.168.154.131 6379
# windows中设置
slaveof 192.168.154.131 6379 # 主机IP + 端口
port 6378 # 从机端口
- 开启主机 / 从机服务
# 开启主机服务
src / redis-server redis.conf
# 开启从机服务
src / redis-server slave.conf
- 数据操作
# 进入从的客户端
src / redis -cli -h 192.168.154.131 -p 6379 # 连接主服务器
src / redis -cli -h 192.168.154.131 -p 6378 # 连接从服务器
- 主从数据库自动同步
# 主数据库
set name lcl
# 从数据库
get name
- 哨兵(sentinel)是 Redis高可用性解决方案
- Sentinel实例组成集群监控 Redis集群服务器,
- 当主服务器下线是, Sentinel可以将该主服务器下的某一个从服务器提升为主服务器进行使用
#1 安装redis5.0
mkdir redis-master
cd /var/redis-5.0.5/src/
make install PREFIX=/var/redis-ms/redis-master
cp /var/redis-5.0.5/redis.conf /var/redis-ms/redis-master/bin
#2 修改redis.conf
# 将`daemonize`由`no`改为`yes`
daemonize yes
# 默认绑定的是回环地址,默认不能被其他机器访问
# bind 127.0.0.1
# 是否开启保护模式,由yes该为no
protected-mode no
#安装redis-slaver1
mkdir redis-slaver1
cp -r /var/redis-ms/redis-master/* /var/redis-ms/redis-slaver1
#修改配置文件
vim /var/redis-ms/redis-slaver1/redis.conf
port 6380
replicaof 127.0.0.1 6379
#安装redis-slaver2
mkdir redis-slaver2
cp -r /var/redis-ms/redis-master/* /var/redis-ms/redis-slaver2
#修改配置文件
vim /var/redis-ms/redis-slaver2/redis.conf
port 6381
replicaof 127.0.0.1 6379
#安装redis-sentinel1
mkdir redis-sentinel1
cp -r /var/redis-ms/redis-master/* /var/redis-ms/redis-sentinel1
#拷贝sentinel.conf 配置文件并修改
cp /var/redis-5.0.5/sentinel.conf /var/redis-ms/redis-sentinel1
# 哨兵sentinel实例运行的端口 默认26379
port 26379
# 将`daemonize`由`no`改为`yes`
daemonize yes
# 哨兵sentinel监控的redis主节点的 ip port
# master-name 可以自己命名的主节点名字 只能由字母A-z、数字0-9 、这三个字符".-_"组成。
# quorum 当这些quorum个数sentinel哨兵认为master主节点失联 那么这时 客观上认为主节点失联了
# sentinel monitor
sentinel monitor mymaster 127.0.0.1 6379 2
# 当在Redis实例中开启了requirepass foobared 授权密码 这样所有连接Redis实例的客户端都要提
供密码
# 设置哨兵sentinel 连接主从的密码 注意必须为主从设置一样的验证密码
# sentinel auth-pass
sentinel auth-pass mymaster MySUPER--secret-0123passw0rd
# 指定多少毫秒之后 主节点没有应答哨兵sentinel 此时 哨兵主观上认为主节点下线 默认30秒,改成3秒
# sentinel down-after-milliseconds
sentinel down-after-milliseconds mymaster 3000
# 这个配置项指定了在发生failover主备切换时最多可以有多少个slave同时对新的master进行 同步,这个数字越小,完成failover所需的时间就越长,但是如果这个数字越大,就意味着越 多的slave因为replication而不可用。可以通过将这个值设为 1 来保证每次只有一个slave 处于不能处理命令请求的状态。
# sentinel parallel-syncs
sentinel parallel-syncs mymaster 1
# 故障转移的超时时间 failover-timeout 可以用在以下这些方面:
#1. 同一个sentinel对同一个master两次failover之间的间隔时间。
#2. 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那里同步数据时。
#3.当想要取消一个正在进行的failover所需要的时间。
#4.当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超时,slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了
# 默认三分钟
# sentinel failover-timeout
sentinel failover-timeout mymaster 180000
"""
启动redis-master和redis-slaver
在redis-master目录下 ./redis-server redis.conf
在redis-slaver1目录下 ./redis-server redis.conf
在redis-slaver2目录下 ./redis-server redis.conf
#启动redis-sentinel
在redis-sentinel1目录下 ./redis-sentinel sentinel.conf
在redis-sentinel2目录下 ./redis-sentinel sentinel.conf
在redis-sentinel3目录下 ./redis-sentinel sentinel.conf
"""
#查看启动状态
[root@localhost bin]# ps -ef |grep redis
root 3602 1 0 01:33 ? 00:00:00 ./redis-server *:6379
root 3647 1 0 01:37 ? 00:00:00 ./redis-server *:6380
root 3717 1 0 01:40 ? 00:00:00 ./redis-server *:6381
root 3760 1 0 01:42 ? 00:00:00 ./redis-sentinel *:26379
[sentinel]
root 3765 1 0 01:42 ? 00:00:00 ./redis-sentinel *:26380
[sentinel]
root 3770 1 0 01:42 ? 00:00:00 ./redis-sentinel *:26381
[sentinel]
root 3783 2261 0 01:42 pts/0 00:00:00 grep --color=auto redis