程序员学点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.创建基本环境 ...
随机推荐
- 如何写md格式的文档
一.标题 标题其实和HTML中的h系列很像,想要设置为标题的文字前面加#来表示一个#是一级标题,二个#是二级标题,以此类推.支持六级标题. 注:标准语法一般在#后跟个空格再写文字, 示例: 效果如下: ...
- 一个纯CSS实现的卡片翻转效果
先上代码 <div id="box"> <div class="front">正面</div> <div class= ...
- Ubuntu16.04安装Docker、nvidia-docker
Ubuntu16.04安装Docker.nvidia-docker Docker安装 1.更换国内软件源,推荐中国科技大学的源,稳定速度快(可选) sudo cp /etc/apt/sources.l ...
- 落谷P3941 入阵曲
题目背景 pdf题面和大样例链接:http://pan.baidu.com/s/1cawM7c 密码:xgxv 丹青千秋酿,一醉解愁肠. 无悔少年枉,只愿壮志狂. 题目描述 小 F 很喜欢数学,但是到 ...
- CountDownLatch源码及Javadoc阅览
/** * A synchronization aid that allows one or more threads to wait until * a set of operations bein ...
- Web安全之注入点构造
在测试过程中,经常需要自己本地构造注入点来进行SQL测试,这边分享一下,不同环境下构造SQL注入的代码. PHP+MYSQL版 <?php $con = mysql_connect(" ...
- Spring Security 整合JWT(四)
一.前言 本篇文章将讲述Spring Security 简单整合JWT 处理认证授权 基本环境 spring-boot 2.1.8 mybatis-plus 2.2.0 mysql 数据库 maven ...
- Docker安装ELK并实现JSON格式日志分析
ELK是什么 ELK是elastic公司提供的一套完整的日志收集以及前端展示的解决方案,是三个产品的首字母缩写,分别是ElasticSearch.Logstash和Kibana. 其中Logstash ...
- php服务器有哪些
服务器按照功能可以分为:文件服务器.数据库服务器.web服务器.邮件服务器.代理服务器..... 而上述所有的服务器,均可以用php做开发,比如说做web服务器,常用的构架是php+Mysql+Apa ...
- 将 so|JNI|NDK 之间的关系说明白
最近在了解公司历史的发展,发现了公司产品中几乎都要使用 so 文件,不禁好奇这个 so 到底是何方神圣. so 文件 so 是 shared object 的缩写,见名思义就是共享的对象,机器可以直接 ...