程序员学点xx 之 Redis
程序员学点xx 之 Redis
概述
其实程序员也要和操作系统打交道, 比如最常见的,部署自己电脑上的开发环境.
当然有时某些牛人, 觉得运维或基础部门的同事不够给力, 亲自上手部署服务器或线上环境,这种情况也是存在的.综上所述, 程序员和运维接触的东西是一致的, 只是涉及群集或动作原理上会差一点点.
我的目的,就是花点时间把这些运维的细碎知识梳理一下, 保证被人问起来完全不虚.
群集
单独的redis大家应该都会部署了, 下载源码包, 编译一下就成. 或者使用docker 命令 pull 一下.
下面来说群集 CLUSTER
一般 CLUSTER 习惯布6台: 3主 3从
如果单台会部署的话,其实也很简单
修改一下 redis.conf, 把监听端口, 节点等选项打开就行了
主要涉及下列项目:
- 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 对容器的支持不好
茶歇
面试别人还是很有技巧的,比如:
- 用容器搭一个redis出来
- 你知道redis-trib.rb文件么
- 如何用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
承前
三天都在说使用集群的相关的知识, 今天来说明一下集群的工作原理.
虽然都是官方提供的东西:
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 发布!
最新内容欢迎关注公众号:
程序员学点xx 之 Redis的更多相关文章
- 0基础入门 docker 部署 各种 Prometheus 案例 - 程序员学点xx 总集篇
目录 大家好, 学点xx 系列也推出一段时间了.虽然 yann 能力有限,但还是收到了很多鼓励与赞赏.对这个系列 yann 还是很喜欢的,特别是 Prometheus 篇,在期间经历公众号 100 篇 ...
- 你浏览器的书签栏还够用么? - 程序员学点xx 特辑
lluxury 运维开发时间 为什么会想到这个话题,是因为最近看到的一条广告:注册 xx 送2048GB资料.yann 暗自感慨:"都9012年了,还有人分享家里的祖传硬盘".2T ...
- 构建CRD工程 - 程序员学点xx 43 k8s
目录 Kubernetes -3- 这是yann的第98篇分享 本日状态: 帮同事排了一天bug. Kubernetes -3- 这是yann的第98篇分享 第 1 部分 承前 昨天用视屏的方式演 ...
- 成为k8s大佬,从这个操作开始(伪) - 程序员学点xx 42 k8s
目录 Kubernetes -2- 这是yann的第97篇分享 本日状态: 饿着肚子写公众号的 yann 同学. 第 1 部分 反省 昨天的内容被熊哥批评了. 熊哥说,「你光想着自己爽,一句我认为 ...
- .Net程序员学用Oracle系列(10):系统函数(下)
<.Net程序员学用Oracle系列:导航目录> 本文大纲 1.转换函数 1.1.TO_CHAR 1.2.TO_NUMBER 1.3.TO_DATE 1.4.CAST 2.近似值函数 2. ...
- CSharp程序员学Android开发---1.初识AndriodIDE,掌握工具使用
最近公司组织项目组成员开发一个Android项目的Demo,之前没有人有Andoid方面的开发经验,都是开发C#的. 虽说项目要求并不是很高,但是对于没有这方面经验的人来说,第一步是最困难的. 项目历 ...
- C++程序员学Python
目录 C++程序员学Python 第二章.变量和数据类型 1.注释语句前用#: 2.常用于大小写函数: 第三章.列表 1.列表简述 2.修改,增加,插入,删除列表元素 第四章操作列表 1.遍历 2.创 ...
- .Net程序员学用Oracle系列(1):导航目录
本人从事基于 Oracle 的 .Net 企业级开发近三年,在此之前学习和使用的都是 (MS)SQL Server.未曾系统的了解过 Oracle,所以长时间感到各种不习惯.不方便.怪异和不解,常会遇 ...
- .Net程序员学用Oracle系列(2):准备测试环境
<.Net程序员学用Oracle系列:导航目录> 本文大纲 1.创建说明 1.1.为什么要创建的测试环境? 1.2.了解 Oracle 实例的默认用户 2.创建环境 2.1.创建基本环境 ...
随机推荐
- 【MySQL】java.sql.SQLException: The server time zone value
错误:Could not open JDBC Connection for transaction; nested exception is java.sql.SQLException: The se ...
- mpvue 页面预加载,新增preLoad生命周期
存在的必要性:mpvue开发微信小程序,在页面跳转到新页面的过程中会有200ms左右的延迟,这个200ms如果用来请求新页面的接口,那么跳转到新页面或许已经渲染好了页面. 就是两种方式: 1.新页面跳 ...
- 从零开始入门 K8s | Kubernetes 网络概念及策略控制
作者 | 阿里巴巴高级技术专家 叶磊 一.Kubernetes 基本网络模型 本文来介绍一下 Kubernetes 对网络模型的一些想法.大家知道 Kubernetes 对于网络具体实现方案,没有什 ...
- 车载导航应用中基于Sketch UI主题定制方案的实现
1.导读 关于应用的主题定制,相信大家或多或少都有接触,基本上,实现思路可以分为两类: 内置主题(应用内自定义style) 外部加载方式(资源apk形式.压缩资源.插件等) 其实,针对不同的主题定制实 ...
- unittest介绍
unittest框架是python中一个标准的库中的一个模块,该模块包括许多的类如 test case类.test suit类.texttest runner类.texttest resuite类.t ...
- Java编程思想——第17章 容器深入研究 读书笔记(四)
九.散列与散列码 HashMap使用equals()判断当前的键是否与表中存在的键相同. 正确的equals()方法需满足一下条件: 1)自反性.x.equals(x) 是true; 2)对称性.x. ...
- Zabbix 2.2系列注入+getsehll
Zabbix 是一个开源的企业级性能监控解决方案. 官方网站:http://www.zabbix.com Zabbix 的jsrpc的profileIdx2参数存在insert方式的SQL注入漏洞,攻 ...
- Git上传项目至GitHub
要使用github,首先需要下载git.安装git 1.先在github上创建一个git仓库,复制该github路径 2.用cmd进入一个目录 git clone github路径 从github上直 ...
- 新手也能看懂的 SpringBoot 异步编程指南
本文已经收录自 springboot-guide : https://github.com/Snailclimb/springboot-guide (Spring Boot 核心知识点整理. 基于 S ...
- 收益 or 挑战?Serverless 究竟给前端带来了什么
作者 | 黄子毅(紫益) 阿里前端技术专家 导读:前端开发者是最早享受到 "Serverless" 好处的群体,因为浏览器就是一个开箱即用.甚至无需为计算付费的环境!Serverl ...