程序员学点xx 之 Redis

程序员学点xx 之 Redis

mark

概述

其实程序员也要和操做系统打交道, 好比最多见的,部署本身电脑上的开发环境.node

固然有时某些牛人, 以为运维或基础部门的同事不够给力, 亲自上手部署服务器或线上环境,这种状况也是存在的.综上所述, 程序员和运维接触的东西是一致的, 只是涉及群集或动做原理上会差一点点.mysql

个人目的,就是花点时间把这些运维的细碎知识梳理一下, 保证被人问起来彻底不虚.程序员

群集

单独的redis你们应该都会部署了, 下载源码包, 编译一下就成. 或者使用docker 命令 pull 一下.面试

下面来讲群集 CLUSTERredis

通常 CLUSTER 习惯布6台: 3主 3从算法

若是单台会部署的话,其实也很简单sql

修改一下 redis.conf, 把监听端口, 节点等选项打开就好了docker

主要涉及下列项目:数据库

  • bind
  • daemonize
  • requirepass
  • masterauth
  • logfile
  • cluster-enabled
  • cluster-config-file
  • cluster-node-timeout
  • dbfilename
  • appendfilename

修改完成后, 把6台redis 启动起来, 登陆进redis浏览器

/root/docker_redis_cluster/redis-3.2.11/src/redis-cli -h 127.0.0.1 -p 6379
auth 123456
info replication

而后用meet命令把其余群集加入进来便可

CLUSTER MEET 172.17.0.3 6379 
CLUSTER MEET 172.17.0.4 6379 
...
CLUSTER NODES

须要分配下槽位

redis-cli -p 6379 cluster addslots {0..5461}
redis-cli -p 6380 cluster addslots {5462..10922}
redis-cli -p 6381 cluster addslots {10923..16383}
CLUSTER NODES

分配的3台就是主了

登陆另外3台服务器, 分别把主添加给本身, 集群就完成了

CLUSTER NODES
CLUSTER REPLICATE 760e4d0039c5ac13d04aa4791c9e6dc28544d7c7
# 分别登陆从机,加入主服务器的id

茶歇

昨天搞定了redis的集群, 原本是没什么问题了, 但看完关于矫情的记述后我以为, 必定会有人跳出来:

"low货,人家redis集群都是用集群脚本安装的."

做为一个9012年的猿, 虽然yann以为能够举100个理由证实集群脚本的不方便性, 但脚本自己仍是能够了解一下的.

脚本安装

这里所说的脚本是叫作 redis-trib 的rb脚本.

虽然100个理由比较难, 但少数不用的理由仍是举的出来的:

  • 须要ruby环境
  • 对容器的支持很差
  • 不支持密码

下面逐条开撕:

须要ruby环境
yum install ruby
# 或 apt-get install ruby
gem install redis

这里还会有一个坑:

gem时系统会报ruby的版本过低

至于如何使用rvm修改版本就是另外一篇文了

对于洁癖人士 (好比yann)来讲, 无故在系统里安装ruby是不可接受的.

何况还有衍生问题,后面会叙述.

命令参数

cd /usr/local/src/redis-3.2.11/src
./redis-trib.rb help
create 
check
info 
fix
reshard
建立集群
./redis-trib.rb create --replicas 1 127.0.0.1:6479 127.0.0.1:6480 127.0.0.1:6481 127.0.0.1:6482 127.0.0.1:6483 127.0.0.1:6484

​ ps. 若是须要指定服务器为从库, 只能先添加3台, 再经过新增节点指定其对应主库

不支持密码

第二点理由爆发了.

redis-trib.rb 会报没法链接集群, 须要修改client.rb文件

修改源码文件后, 脚本链接上了集群,继续其余操做

测试集群
./redis-trib.rb check 127.0.0.1:6479
查看信息
./redis-trib.rb info 127.0.0.1:6479
平衡节点

根据权重分配, 比较有用的功能之一

./redis-trib.rb rebalance 127.0.0.1:6479
删除节点

只能删除没有分配slot的节点

./redis-trib.rb del-node 127.0.0.1:6480
添加节点

加主库注意添加的服务器在前, 加从库须要主库id

./redis-trib.rb add-node 127.0.0.1:6488 127.0.0.1:6479

./redis-trib.rb add-node --slave --master-id 77c2a2d5e96d14a4c5b5614cb68ad27d40530f4b 127.0.0.1:6480 127.0.0.1:6479
踩坑

其实上面的操做通通没有完成.

缘由很简单, yann使用容器搭的redis

会有2个ip, 容器外ip和容器内ip.

使用容器内ip脚本运行不起来, 而使用容器外ip的话,脚本完成不了. 缘由请本身想一下.

到这一步,算掉到坑里出不来了, 虽然在容器内部安装ruby能够解决, 但容器是精简系统, redis文件也不全...

redis-trib.rb 对容器的支持很差

茶歇

面试别人仍是颇有技巧的,好比:

  1. 用容器搭一个redis出来
  2. 你知道redis-trib.rb文件么
  3. 如何用redis-trib.rb和刚才搭的redis作一个集群出来

答案是作不出来, 缘由请看昨天的巨坑.


生产操做

搞定了群集以后就能够作一些具体的工做了, 例如:

  • 槽位迁移
  • 再平衡
  • 单机迁移到群集
槽位迁移

为何要进行槽位迁移呢?

固然是为了集群的扩容/缩容啊.

redis的槽位实际上是很重要的概念.

槽位不分配掉, 集群不能使用,

存在槽位的节点不能删除,

槽位只分配在主节点上...

曹魏: 说我么?

没有, 快滚...

在线迁移, 用来完成集群的在线横向扩容和缩容

./redis-trib.rb reshard 127.0.0.1:6479# 检查以后会出现交互信息, 询问迁移多少槽位,到哪一个节点之类

参数迁移

生产中经常使用的方式

./redis-trib.rb reshard --from 7fa64d250b595d8ac21a42477af5ac8c07c35d83 --to 5476787f31fa375fda6bb32676a969c8b8adfbc2 --slots 10 127.0.0.1:6479
再平衡

新加入节点后, 槽位变的不平衡,能够用 rebalance 处理.

一样有密码的问题, 修改rb文件或配置文件上取消密码看各人爱好.

./redis-trib.rb rebalance 127.0.0.1:6479
单机迁移到集群

经常使用来处理历史问题,

当年需求急, 单枪匹立刻线了12345

redis-trib.rb import--from ip:port:id # 源 单机--copy ip:port # 集群

密码问题,一样须要修改文件源码:

vi redis-trib.rb

mark

承前

三天都在说使用集群的相关的知识, 今天来讲明一下集群的工做原理.

虽然都是官方提供的东西:

Redis Cluster采用无中心节点方式实现,无需proxy代理

客户端直接与redis集群的全部节点链接

根据hash算法计算出key对应的slot

在slot对应的Redis上执行命令

以CAP角度来看

Redis Cluster 属于AP

Availability&Partition-Tolerancy

可用并分区容错

安全加固

redis 是系统中的漏洞大户

yann某次不能关机又须要root权限,就是从它这里拿的

私有环境操做, 请勿模仿

总之, 常见的加固以下:

  • 开启redis密码认证
  • 禁止使用root用户启动
  • 修改默认6379端口
  • 限制redis 配置文件访问权限
  • 禁用或者重命名危险命令
  • 禁止监听在公网
  • 打开保护模式

开启redis密码认证

vi redis.conf中 requirepass# 配置强密码

禁止使用root用户启动

useradd -s /sbin/nolog -M redis sudo -u redis /<redis-server-path>/redis-server /<configpath>/redis.conf

修改默认6379端口

vi redis.conf中 port# 80,81,82的兄弟们

限制redis 配置文件访问权限

chmod 600 /<filepath>/redis.conf

禁用或者重命名危险命令

这条倒不是必要的, 毕竟不方便

vi redis.conf中 rename-command DEL ""# 或rename-command FLUSHALL joYAPNXRPmca

禁止监听在公网

vi redis.conf中 bind 127.0.0.1 # 或本地ip

打开保护模式

必要, 没有密码和bind只能本地访问

vi redis.conf中 protected-mode yes

疑问

以前yann有个疑问, 不知道你们会不会有相似的怀疑:

REDIS有主从和哨兵模式了, 要CLUSTER干吗.

这个问题今天会解决

持久化相关命令

参考mysql备份机制

rdb至关于物理备份, aof 至关于 逻辑备份

vi redis.conf
  dbfilename
  appendfilename
# 主要参数及上下方相似名字的各类设置参数
从库换主

作法: 把从库清空而后重新主库完整同步一份数据再进行续传.

重作流程
  • 主库bgsave自身数据到磁盘
  • 主库发送rdb文件到从库
  • 从库开始加载
  • 加载完毕开始续传,同时开始提供服务
现实数据

一但数据量超过20GB, 复制时间超过20分钟

多台从库, 时间会倍增. 同时须要考虑网卡瓶颈

使用内存限制

vi redis.conf
maxmemory
从库扩容

一样问题, 从库扩容也会遇到.

当遇到流量暴增,应急性扩容, 以上扩容一样须要20分以上

若是仍然接受数据, 中断时间过长同步缓冲区被覆盖,从新同步

持久化进程阻塞Redis主线程, 20G内存耗时约为750ms


话题

都知道Redis很快, 可是有多快呢.

QPS测试

环境

i5 CPU 8GB 内存

REDIS测试工具
cd src  
./redis-benchmark -n 1000000 -t set,get -q
# SET: 48936.32 requests per second
# GET: 51290.85 requests per second

REDIS 的大体数据约5w

MYSQL测试工具

sysbench

url -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.deb.sh | sudo bash
sudo apt -y install sysbench

mysql -uroot -p -e"create database benchmark"

sysbench /usr/share/sysbench/oltp_read_write.lua --mysql-user=root --mysql-password=root --mysql-db=benchmark --tables=10 --table-size=1000000 --events=100000000 --report-interval=10 --threads=4 --time=300 prepare

sysbench /usr/share/sysbench/oltp_read_write.lua --mysql-user=root --mysql-password=root --mysql-db=benchmark --tables=10 --table-size=1000000 --events=100000000 --report-interval=10 --threads=4 --time=300 run

由于使用的阿里云RDS, 这个操做我没有作

相同配置服务器反馈是4000左右

单线程REDIS

数据都在内存, 单线程去操做效率最高

多线程存在上下文的切换

一次CPU上下文的切换约 1500ns

从内存中读取 1MB 的连续数据,耗时大约为 250us

假设多线程读取了1000次,光切换耗时1500ns * 1000 = 1500us

多线程REDIS

Redis 6 引入的多线程 IO 特性

优化方向

提升网络 IO 性能,使用 DPDK

动用多个核心运行多线程, 仅用在处理网络数据和协议解析

实现原理
  • 主线程接收建连请求,读事件放队列处理
  • 主线程将链接分配给其余 IO 线程,而后主线程等待
  • IO 线程将请求数据读取并解析
  • 主线程执行命令并清空队列
性能对比
vi redis.conf
  io-threads 4
  io-threads-do-reads yes
# 仅记录, 拿到后测试一下, 须要gcc 5.0+
redis-benchmark -h 192.168.0.49 -a foobared -t set,get -n 1000000 -r 100000000 --threads 4 -d ${datasize} -c 256

周报

Redis也看了一周了, 天天测试,记笔记, 总结...

感受能够暂停一下了, 明天会有新的东西.

如下以Redis的最后一部分


缓存雪崩

所谓缓存雪崩就是缓存挂掉了,所有请求都跑去找数据库了

这里有2个前提:

  • 业务流量大
  • 系统没有降级限流设置措施

先说流量, Mysql 5.7 默认最大链接数200, 一般会配置成2000, 加上只读库能够看做4000. 加上广泛链接池运做, 通常能够抗一段时间, 坚持到redis拉起来.

再说限流, SpringCloud和 Dubbo 均可以有 Hystrix, 比较核心的业务, 建议配置起来.

如何解决缓存雪崩?

基于系统的故障老是好解决的

Redis集群也好, 对其自己的监控或对Mysql的监控也好, 均可提醒有故障了, 去处理.

难的是逻辑上的故障

好比写死过时时间, 结果同时所有过时,

再好比新功能上线直接没缓存. 须要缓存预热等.


缓存穿透

缓存穿透就很简单了, 就是一直请求不存在的参数.

结果 Redis就没东西提供, 直接交给数据库处理了.

一样和数量有关, 少许够不成危害. 而大量的话, redis命中率偏低, 直接会有报警出来.

解决方式也有二种:

要么布隆过滤不合理参数, 要么干脆缓存空对象, 使用哪一种方式, 就看本身方便了.


REDIS与MYSQL 一致性

缓存什么都好, 就是一致性让人头疼. 不光Redis和Mysql, 浏览器的缓存, 甚至CDN, 一切缓存相关的问题都让人头疼.

读操做

若是数据在缓存里边有,那么直接取缓存返回。

若是缓存里没有, 先去查询数据库,而后将结果写到缓存中。最后将数据返回给请求。

写操做

先更新数据库, 再操做缓存失败.

优雅一点的作法是, 在MySQL端定义CRUD触发器,或在Redis端解析binlog, 进行操做.

更现实的作法是, 用消息队列保证更新操做可以完成, 甚至对一样数据的请求放在一个队列里, 固然也可能所有卡住.

更新缓存

这里没有涉及更新缓存, 事实上定时更新也好, 逻辑判断有效性也好, 都是基于业务特性来决定的.

缓存算法

FIFO 先进先出

LRU 近期最少使用, 使用时间差别

LFU 最不常用, 次数差别

注: Redis 4.0 才有LFU.


总结

从1号到如今, 走马观花写了不少. 大部分都关注于坑和生产应用, 对平常使用Redis的记录比较少.

没办法, 时间仍是不够. 就算强力驱动着本身仍是浅尝辄止. 任何一个应用均可以静下心来揣摩一个月, 可是没有时间.

如今只能拼命吃一点, 以求遇到的时候不要没有思路. 其余只能后续研究了. 共勉!

本文由博客一文多发平台 OpenWrite 发布!
最新内容欢迎关注公众号:
https://img2018.cnblogs.com/blog/1270617/201911/1270617-20191112111025320-437079521.jpg

相关文章
相关标签/搜索