安装redis
配置网络
cd /etc/sysconfig/network-scripts #进入网络配置目录
dir ifcfg* #找到网卡配置文件
ifcfg-ens33 #找到版本最新的文件并修改
vim ifcfg-ens33
或者
vim /etc/sysconfig/network-scripts/ifcfg-ens33
TYPE=Ethernet
BOOTPROTO=static #改成static,针对NAT
NAME=eno16777736
UUID=4cc9c89b-cf9e-4847-b9ea-ac713baf4cc8
DEVICE=eno16777736
DNS1=114.114.114.114 #和网关相同
ONBOOT=yes #开机启动此网卡
IPADDR=192.168.64.101 #固定IP地址
NETMASK=255.255.255.0 #子网掩码
GATEWAY=192.168.64.2 #网关和NAT自动配置的相同,不同则无法登录
service network restart #重启网络
systemctl restart network.service #重启网络centos7
或者重启机器
官网下载Redis
几种方式
- wget 地址
- 其他方式获取到 tar文件
解压tar文件
tar xf tar文件
阅读README.md文件
步骤
- 安装在指定目录下
make install PREFIX=/opt/soft/redis6.0
- 设置REDIS_HOME
vi /etc/profile
# 在文件最后加
export REDIS_HOME=/opt/hxwang/redis6.0
export PATH=$PATH:$REDIS_HOME/bin
- 在源码的utils 目录下执行
./install_server.sh
这个地方可能会报错
Welcome to the redis service installer
This script will help you easily set up a running redis server
This systems seems to use systemd.
Please take a look at the provided example service unit files in this directory, and adapt and install them. Sorry!
如果出现了这个错误
vi install_server.sh
注释掉下面几行
#_pid_1_exe="$(readlink -f /proc/1/exe)"
#if [ "${_pid_1_exe##*/}" = systemd ]
#then
# echo "This systems seems to use systemd."
# echo "Please take a look at the provided example service unit files in this directory, and adapt and install them. Sorry!"
# exit 1
#fi
保存退出,即可解决
- 将redis做成服务
vi /etc/profile # 配置文件中配置环境变量
# 在文件最后加
export REDIS_HOME=/opt/hxwang/redis6.0 # 安装目录
export PATH=$PATH:$REDIS_HOME/bin
# 保存退出后刷新
source /etc/profile
echo $PATH
- 开机会自动启动
手动启动
service redis_端口号
- utils目录下的 ./install_server.sh 可启动多个 通过端口区分
redis 知识
redis是单线程单实例的(那为何处理并发时也很快呢?)
redis默认的有16 个库可在配置文件中修改,每个库的空间是隔离的
二进制安全
redis保存的是字节信息会根据客户端编码的不同而改变字符
使用redis-cli --raw
就可以使用字符编码
使用get
就可以获取字符,不再是16进制数
但是使用strlen
命令时依然获取字节的长度
redis 命令
redis-cli 端口 #进入redis客户端
select 分区索引 # 进入指定的库
在 key 中会有一个 type 的属性–描述的是value的类型,当操作方法与类型不匹配时,不用发生实际的操作只要方法和类型不匹配就会报错
object encoding key # 获取value的类型
string
set 设置值
set k1 hello nx # 当k1不存在时才能set(分布式锁时使用)
set k2 hello xx # 只有存在k2时才可以set (只可以更新)
mset k3 a k4 b # 可以设置多个值
mget k3 k4 # 可以取出多个值
msetnx # 批量set 是原子性的(一个失败则全部失败)
GETSET k2 # 返回旧值赋予新值(为了增加效率会减少一次IO通信)
append 字符串拼接
append k1 " world" # 对值进行追加
getrange k1 6 10 # word 按索引取值,支持反向索引
setrange k1 6 hxwang # 从指定位置进行覆盖
strlen k1 # 获取长度
incrby 对数字加。。
incr k1 # 默认加1
incrby k1 3 # 指定加3
INCRBYFLOAT 加小数
decr 递减
decr k1 # 减1
decrby k1 3 # 减3
二进制 归属于string
setbit
给指定的位置设置1或0
offset 指的是位的索引
一个字节是8位 所以长度小于一个字节为1
bitpos
bit -> 0或1
start -> 字节的索引
end -> 字节的索引
返回 bit第一次出现的位的索引
bitcount 返回字节范围内位上为1 的个数
bitop 进行二进制与或计算
BITOP and andkey k1 k2 按位与操作
BITOP OR ORKEY k1 k2 按位或操作(有1则1)
统计活跃用户的问题 ==> 将每个位对应一个用户
list 列表
BLPOP ---- 删除并返回列表中的第一个元素(如果列表中没有数据可以阻塞相应的时间)
LTRIM ---- 对给定范围外的数据进行删除
hash
set 不重复集合
SINTER 返回两个集合的交集
SINTERSTORE 将两个集合的交集放入一个新的集合中
这个命令将数据交换在客户端完成,数据没有进入IO节省了时间
SUNION 返回两个集合的并集
SDIFF 差集(是有方向性的)
SRANDMEMBER KEY COUNT (随机事件 COUNT 为正数时 取出一个去重的结果集合(不能超过已有集合)为负数时 取出一个带重复的结果集一定会满足的数量 为0时不返回)
可以做抽奖的方案(可以一次取多个)
sorted_set 有序集合
物理内存从小到大且不随命令变化/支持数值计算
ZADD — 添加值 score 为分值 number 为元素
ZINCRBY — 对分值进行计算增加或者减少,然后根据分值物理顺序会重新排列
ZUNIONSTORE — 集合的交集(不给权重(权重是旧的分值乘权重获取新的分值)和聚合参数时,默认的是分值相加)
排序是怎么实现的? 增删改查的速度?
采用跳跃表(类平衡树)数据结构(除了前后指针还有上下指针分为了多层(随机造层))
管道 — 开启管道后效率会提升5倍(减少网络IO时间)
可以将多个命令发送到服务器,而不用等待回复,最后在一个步骤中读取该答复。
这就是管道(pipelining),是一种几十年来广泛使用的技术。例如许多POP3协议已经实现支持这个功能,大大加快了从服务器下载新邮件的过程。
Redis很早就支持管道(pipelining)技术
重要说明: 使用管道发送命令时,服务器将被迫回复一个队列答复,占用很多内存。所以,如果你需要发送大量的命令,最好是把他们按照合理数量分批次的处理,例如10K的命令,读回复,然后再发送另一个10k的命令,等等。这样速度几乎是相同的,但是在回复这10k命令队列需要非常大量的内存用来组织返回数据内容。
发布订阅 — pubsub
PUBLISH — 将消息放入通道
SUBSCRIBE — 监听对应的通道,通道有消息就会显示
事务
- redis是单线程-当多个客户端开启事务时命令并不会直接执行而是将命令放在一个队列中那个事务先提交那个事务就先执行
MULTI — 开启事务
EXEC — 提交事务
WATCH — 检查key(在开启事务前,实现乐观锁-CAS操作(check-and-set))
如果提交事务时发现key被修改了则事务的命令都不会执行
布隆过滤器(解决缓存穿透)
缓存穿透:缓存中没有数据库中也没有的数据,数据库就会去建立连接去请求来消耗资源
解决方案:
安装
wget https://github.com/RedisBloom/RedisBloom/archive/v2.2.1.tar.gz # 不要用master分支
tar -zxf v2.2.1.tar.gz
cd RedisBloom-2.2.1/
make # 生成redisbloom.so
cp redisbloom.so /opt/hxwang/redis6.0/ # 将文件复制到redis目录下
重启redis
service redis_6379 stop # 停止redis服务
redis-server redis-server /etc/redis/6379.conf --loadmodule /opt/hxwang/redis6.0/redisbloom.so
# 依赖配置文件启动redis 挂载布隆过滤器 (挂载写绝对路径)
启动后会多了BF和CF 的命令
原理
将我们拥有的数据通过多个映射函数映射在 bitmap中进行标记,如果请求的数据通过映射函数命中了bitmap中的标记,很大概率我们是有这个数据的进行放行去缓存中获取或请求数据库,可以很大程度上减少对我们没有数据的请求的放行(而且轻量效率高)
缓存和数据库的区别
- 缓存数据没那么重要(不是全量数据)
- 缓存应该随着访问变化(放的是热数据)
缓存(击穿,雪崩,穿透)
- 击穿:
- key过期,通过算法(LRU/LFU)清除掉了一些key这时有大量并发访问数据,导致去直接访问数据库
解决:
1. get() 失败 发现没有key
2. setnx() -->设置锁(过期时间 防止死锁)
3. 只有获得锁的可以请求数据库
4. 其他设置锁失败的休眠,过后继续get()
- 雪崩
-
大量的key同时失效,造成大量的访问数据库
-
解决:
- 随机设置过期时间
- 业务需求同一时间过期 使用击穿方案
-
- 穿透
- 用户大量并发访问,redis和数据库中都没有的数据,数据库会做空查询
- 解决:
- 使用布隆过滤器
- 客户端使用布隆过滤器的算法 redis的压力都没有
- redis集成布隆过滤器
- 客户端有算法–redis中有bitmap
- 只能增加不能删除(布谷鸟可以删除)
- 使用布隆过滤器
- 双写
- 缓存一致性
redis怎么只保留热数据?
key的有效期(业务逻辑来决定)
- 时间快过期时去访问不会延长
- key发生写时会取出时间
- 因为内存大小有限,随着访问的变化淘汰冷数据(业务运转)
过期原理
牺牲内存来保证性能
- 被动:key过期后还会占用内存,当再次访问key时发现过期 ,返回nil并从内存中清除
- 主动:是一个算法每10秒进行一次
- 随机选20个key进行过期检测
- 删除过期的key
- 如果过期的key多于25%,重复步骤1
Redis 持久化
管道
- 衔接前边命令的输出作为后面命令的输入
- 会触发创建子进程
父子进程
- 进程间的数据应该是隔离的
- 父进程的数据可以让子进程看到(子进程的修改不会破坏父进程父进程修改不会破坏子进程)
创建子进程 fork() (copy on write)
并非拷贝 而是将虚拟地址映射到相同的物理地址 (父进程修改后,子进程去写入时才会复制父进程修改的数据)
RDB 快照
AOF
将Redis的写操作记录在文件中
新版本中AOF文件中是RDB和AOF混合使用上面的部分使用RDB后面的部分使用AOF
- 丢失数据少
- 数据量大时恢复慢
- Redis中,RDB和AOF同时开启时恢复是用AOF
- 4.0 版本前和4.0以后对比
- 写操作会触发IO — 会有三个级别
写操作会先写入缓存区 通过内核去写入磁盘- no – 可能会丢一个缓存区的数据(缓存区满时才会刷入磁盘)
- AWAYS --数据最可靠
- 美秒 – 美秒钟会从缓存区 buffer 写入磁盘
Redis 集群
主从复制
使用,命令:slaveof IP 端口 可以使从服务器跟随主服务器
5.0 版本以后使用 REPLICAOF IP 端口
使用命令 REPLICAOF no one 将从节点设置为主节点
- 从节点 只能读不能写(可以在配置文件中修改)
- 主节点生成一个RDB文件,从节点会去同步主节点的数据(传递RDB文件)
- 在主节点可以知道那个从节点连接过主节点同步过数据
主从的数据持久化
- 从节点连接时, 从节点会将老数据删除
- 当从节点挂掉后重新连接(主节点没有生成RDB文件,从节点也有在挂掉期间产生的数据)——增量的数据(当AOF关闭时),当AOF开启时从节点会重新刷新数据,全量同步(不碰RDB),从节点的RDB可以记录曾经主节点的ID
配置文件
- replica-serve-stale-data yes “从节点在进行同步数据的这个时间是否允许读取从节点上的旧数据”
- replica-read-only yes “从节点只可以读不可以写”
- repl-diskless-sync no “使用网络进行同步数据,no的情况会使用磁盘的方式再使用网络”
- repl-backlong-size 1mb “增量复制,会有一个队列来存储在从节点挂之后产生的数据如果没有没有超过这个设置的大小就会只传递这部分数据不需要进行RDB文件的全量传递和覆盖,如果超过了就需要进行RDB文件的全量的传递和覆盖(根据业务去进行设置)”
高可用—哨兵(sentinel)(解决了:单点故障、访问压力,没有解决:容量问题)
- 哨兵只监控主节点,通过发布订阅发先其他哨兵
- 当主节点宕机,哨兵选择出新的主节点时,会更改自己的配置文件
配置文件
port 5000 # 端口
# 哨兵监控一个名字为mymaster 的主节点 ID 端口 “2”表示2个哨兵认为故障才会进行故障处理
sentinel monitor mymaster 192.168.64.181 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
启动哨兵的方式
redis-service 配置文件 --sentinel
redis-sentinel
高可用—分布式
分布方案:
最后一种方案适合Redis为缓存时使用,Redis作为数据库的这种场景不适用
解决Redis 连接成本高的问题
lvs: 可以让技术对客户端是透明的
分片集群
每个节点都有 算法 和 其他节点的 hash 槽位
数据分治 后聚合操作很难实现(取集合,事务)
可以让 key 中有相同的部分用相同的部分去进行hash计算,确保可以将数据放在相同的RedisService中
代理模式
使用 twemproxy (推特) 代理集群方案
项目地址:
https://github.com/twitter/twemproxy/tree/master
优点:
- 数据分治
- 客户端只知道一个代理的Redis实例,不知道代理后有几个实例
缺点: - keys * 命令不支持
- 事务 不支持
- 不支持 哨兵
使用 predixy 代理搭建集群方案 (性能较高)
项目地址:
https://github.com/joyieldInc/predixy/tree/1.0.5
- 支持sentinel 模式,可以导入sentinel 配置文件(主从复制哨兵)
- 一个代理可以对多套主从复制,在配置文件中根据主从复制的名称设置要代理的分组
- 支持cluster 可以导入cluster配置文件
- 但是一次只支持一种模式
- 如果代理只连接一套,才可以使用事务
自身的集群
无主模型的多节点的cluster
进入redis/create-cluster
使用脚本执行 start —启动 create ----分配hash槽位
完全分布式的集群:
- 会根据key 计算出的 hash值跳转到对应的redis (redis-cli -c -p )
- 无法使用事务(让其数据放在相同的机器上就可以使用事务(设置key的前缀))
API(java)
Jedis
线程不安全的(使用连接池解决)
- 序列化
1.
lettuce
线程安全