Redis哨兵
# 主从复制存在的问题: #1 主从复制,主节点发生故障,需要做故障转移,可以手动转移:让其中一个slave变成master -哨兵解决 #2 主从复制,只能主写数据,所以写能力和存储能力有限 -集群来解决 # 搭建哨兵的目的 一旦一主多从的架构,主库发生故障,能够自动转移 一主多从架构的:高可用 -redis服务对外高度可用 -django服务项目是否是高可用的? -nginx的转发(负载解决) # 哨兵:sentinel - 1 监控 主从 - 2 故障转移 - 3 通知 # 架构说明 可以做故障判断,故障转移,通知客户端(sentinal其实是一个进程),客户端直接连接sentinel的地址 1 多个sentinel发现并确认master有问题 2 选举触一个sentinel作为领导(选举算法Raft算法(共识算法)) 3 选取一个slave作为新的master 4 通知其余slave成为新的master的slave 5 通知客户端主从变化 6 等待老的master复活成为新master的slave # 只需要配置文件配置好,上面的操作,可以自动来做 # 哨兵配置步骤:(启动三个哨兵---》三个进程) -一台机器:一主连从 -一台机器:启动三个sentinel #### 1 先搭建一主两从配置文件#### #第一个是主配置文件 daemonize yes pidfile /var/run/redis.pid port 6379 dir "/root/redis/data" logfile “6379.log” #第二个是从配置文件 daemonize yes pidfile /var/run/redis2.pid port 6381 dir "/root/redis/data2" logfile “6378.log” slaveof 127.0.0.1 6379 slave-read-only yes #第三个是从配置文件 daemonize yes pidfile /var/run/redis3.pid port 6381 dir "/root/redis/data3" logfile “6377.log” slaveof 127.0.0.1 6379 slave-read-only yes #### 2 启动三个redis服务#### redis-server ./redis_6379.conf redis-server ./redis_6380.conf redis-server ./redis_6381.conf #### 3 三个sentinel 配置文件##### # sentinel_26379.conf sentinel_26380.conf sentinel_26381.conf # 三个配置文件,改一下端口和dir即可 port 26379 daemonize yes dir ./data protected-mode no bind 0.0.0.0 logfile "redis_sentinel3.log" sentinel monitor mymaster 127.0.0.1 6379 2 sentinel down-after-milliseconds mymaster 30000 sentinel parallel-syncs mymaster 1 sentinel failover-timeout mymaster 180000 ### 4 启动哨兵 ./src/redis-sentinel ./sentinel_26379.conf ./src/redis-sentinel ./sentinel_26380.conf ./src/redis-sentinel ./sentinel_26381.conf ## 5 查看哨兵是否正常启动 ps aux |grep redis # 可以看到有三个redis-server和三个哨兵 # 6 哨兵---客户端也可以链接 redis-cli -p 26379 info master0:name=mymaster,status=ok,address=127.0.0.1:6379,slaves=2,sentinels=3 集群名字叫:mymaster,状态ok,主库是:127.0.0.1:6379,有两个从库,哨兵有三个 # 7 停止一个从库---》不会做转移 -不会转移 # 8 停止主库---》故障转移---》有一个从库,会变成主库--》其他从库,复制现在的主库 -即便原来的主库启动,它也是从库了 # 配置文件解释 sentinel monitor mymaster 10.0.0.111 6379 2 sentinel down-after-milliseconds mymaster 30000 sentinel parallel-syncs mymaster 1 sentinel failover-timeout mymaster 180000 解释: sentinel monitor mymaster: 监控一个名为 mymaster 的主服务器,后面跟着主服务器的IP和端口,以及最少需要有多少个哨兵同意才进行故障转移。 告诉sentinel去监听地址为ip:port的一个master,这里的master-name可以自定义,quorum是一个数字,指明当有多少个sentinel认为一个master失效时,master才算真正失效 sentinel down-after-milliseconds: 如果一个服务器在指定的毫秒数内没有响应,则认为它是主观下线。 这个配置项指定了需要多少失效时间,一个master才会被这个sentinel主观地认为是不可用的。 单位是毫秒,默认为30秒 sentinel parallel-syncs: 在故障转移期间,可以有几个从服务器同时进行同步。 这个配置项指定了在发生主备切换时最多可以有多少个slave同时对新的master进行 同步,这个数字越小,完成主备切换所需的时间就越长,但是如果这个数字越大,就意味着越 多的slave因为replication而不可用。可以通过将这个值设为 1 来保证每次只有一个slave 处于不能处理命令请求的状态。 sentinel failover-timeout: 故障转移超时时间
python操作哨兵
# 要在别的机器能用 -1 redis.conf 监听地址:0.0.0.0 -2 sentinel配置,写真正ip地址 sentinel monitor mymaster 10.0.0.111 6379 2 import redis from redis.sentinel import Sentinel # 连接哨兵服务器(主机名也可以用域名) # 10.0.0.101:26379 sentinel = Sentinel([('10.0.0.111', 26379), ('10.0.0.111', 26380), ('10.0.0.111', 26381) ], socket_timeout=5) print(sentinel) # 获取主服务器地址 master = sentinel.discover_master('mymaster') print(master) # 获取从服务器地址 slave = sentinel.discover_slaves('mymaster') print(slave) ##### 读写分离 # 获取主服务器进行写入 # master = sentinel.master_for('mymaster', socket_timeout=0.5) # w_ret = master.set('foo', 'bar') # slave = sentinel.slave_for('mymaster', socket_timeout=0.5) # r_ret = slave.get('foo') # print(r_ret)
redis 集群
#1 主从---》提高并发量 #2 哨兵----》高可用 #3 存在问题 1 并发量:单机redis qps为10w/s,但是我们可能需要百万级别的并发量 2 数据量:机器内存16g--256g,如果存500g数据呢? #4 解决:加机器,分布式 redis cluster 在2015年的 3.0 版本加入了,满足分布式的需求 #5 数据分布(分布式数据库:多台机器存储一份数据) -分布式数据库---》分区方案 ####5.1 哈希分布 数据分散度高,建值分布于业务无关,无法顺序访问,支持批量操作 一致性哈希memcache,redis cluster,其他缓存产品 5.1.1.节点取余分区: 缺点:节点扩容,添加一个节点,存在问题,很多数据需要偏移,总偏移量要大于80%,推荐翻倍扩容,由3变成6,数据量迁移为50%,比80%降低 5.1.2 一致性哈希分区 客户端分片:哈希+顺时针(优化取余) 节点伸缩:只影响临近节点,但是还有数据迁移的情况 伸缩:保证最小迁移数据和无法保证负载均衡(这样总共5个节点,数据就不均匀了),翻倍扩容可以实现负载均衡 5.1.3 虚拟槽分区(redis集群) 预设虚拟槽:每个槽映射一个数据子集(16384个槽),一般比节点数大(redis集群不会超过16384台机器) 良好的哈希函数:如CRC16 服务端管理节点、槽、数据:如redis cluster(槽的范围0–16383) 5个节点,把16384个槽平均分配到每个节点,客户端会把数据发送给任意一个节点,通过CRC16对key进行哈希对16383进行取余,算出当前key属于哪部分槽,属于哪个节点,每个节点都会记录是不是负责这部分槽,如果是负责的,进行保存,如果槽不在自己范围内,redis cluster是共享消息的模式,它知道哪个节点负责哪些槽,返回结果,让客户端找对应的节点去存 服务端管理节点,槽,关系 # 5.2 顺序分布 数据分散度易倾斜,建值业务相关,可顺序访问,支持批量操作 BigTable,HBase 顺序分区 # 原理:100个数据分到3个节点上 1--33第一个节点;34--66第二个节点;67--100第三个节点(很多关系型数据库使用此种方式) # 启动 6个redis节点,一主一从架构 3个节点 存数据,每个有一个从库,做高可用 ----------------------------------------------- # 第一步:写6个redis配置文件 # vi redis-7000.conf port 7000 daemonize yes dir "/root/redis-7.2.4/data/" logfile "7000.log" dbfilename "dump-7000.rdb" cluster-enabled yes cluster-config-file nodes-7000.conf cluster-require-full-coverage yes # 第二步:快速生成剩余5个配置文件 sed 's/7000/7001/g' redis-7000.conf > redis-7001.conf sed 's/7000/7002/g' redis-7000.conf > redis-7002.conf sed 's/7000/7003/g' redis-7000.conf > redis-7003.conf sed 's/7000/7004/g' redis-7000.conf > redis-7004.conf sed 's/7000/7005/g' redis-7000.conf > redis-7005.conf # 第三步;启动6个节点 redis-server ./redis-7000.conf redis-server ./redis-7001.conf redis-server ./redis-7002.conf redis-server ./redis-7003.conf redis-server ./redis-7004.conf redis-server ./redis-7005.conf # 查看集群信息 cluster info cluster nodes # 第四步:搭建集群 redis-cli --cluster create --cluster-replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 # yes 同意 # 第五步:测试 往 7000 上写 set name lqz 这个数据,写不进去 原因是:name被hash后,得到的槽不归 7000管[0--5460槽] 返回给我们错误,让我们去7001上写,顺利写进去 # 第六步:查看机器信息 cluster nodes cluster info # 第六步:集群模式连接--->自动切换到不同节点 redis-cli -p 7000 -c # 第七:停掉一个主---》原来的从会升级为主 # 第八步:python操作redis集群 # pip3 install redis-py-cluster from rediscluster import RedisCluster startup_nodes = [{"host":"127.0.0.1", "port": "7005"},{"host":"127.0.0.1", "port": "7001"},{"host":"127.0.0.1", "port": "7002"}] rc = RedisCluster(startup_nodes=startup_nodes) rc.set("foo", "bar") print(rc.get("foo"))
扩成8台机器--4个节点
#1 准备两台机器 sed 's/7000/7006/g' redis-7000.conf > redis-7006.conf sed 's/7000/7007/g' redis-7000.conf > redis-7007.conf #2 启动两台机器 redis-server ./redis-7006.conf redis-server ./redis-7007.conf # 3 两台机器加入到集群中去 redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000 redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7000 # 4 让7007复制7006 redis-cli -p 7007 cluster replicate 7947d7df93b5a66832068f6baed8af7d823b02c3 # 5 迁移槽 redis-cli --cluster reshard 127.0.0.1:7000 -迁移4096个槽 16384/4 -7006的机器接收槽 -all
缩容成6台机器--3个节点
# 第一步:下线迁槽(把7006的1366个槽迁移到7000上) redis-cli --cluster reshard --cluster-from 7947d7df93b5a66832068f6baed8af7d823b02c3 --cluster-to 6adbf098377c788c5bd47cfa524eae5bb0c6ee32 --cluster-slots 1365 127.0.0.1:7000 yes redis-cli --cluster reshard --cluster-from 7947d7df93b5a66832068f6baed8af7d823b02c3 --cluster-to 427b88b91d86bd876da6f36a7e0b22eabcdc28f2 --cluster-slots 1366 127.0.0.1:7001 yes redis-cli --cluster reshard --cluster-from 7947d7df93b5a66832068f6baed8af7d823b02c3 --cluster-to 21662603b66a0263cd8b581ed58c0c5b041fd255 --cluster-slots 1365 127.0.0.1:7002 yes #第二步:下线节点 忘记节点,关闭节点 redis-cli --cluster del-node 127.0.0.1:7000 408242644423ff0d9d29434f7c7c5450b0ec996f # 先下从,再下主,因为先下主会触发故障转移 redis-cli --cluster del-node 127.0.0.1:7000 7947d7df93b5a66832068f6baed8af7d823b02c3 # 第三步:关掉其中一个主,另一个从立马变成主顶上, 重启停止的主,发现变成了从
缓存
缓存更新策略
# 如果内存中redis数据满了,再继续往里存数据,redis会触发缓存更新的策略 # 有如下几种 LRU/LFU/FIFO算法剔除:例如maxmemory-policy(到了最大内存,对应的应对策略) # LRU -Least Recently Used,没有被使用时间最长的 # LFU -Least Frequenty User,一定时间段内使用次数最少的 # FIFO -First In First Out,最早放进去的key
缓存穿透 缓存击穿 缓存雪崩
### 缓存穿透 #描述: 缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。 #解决方案: 1 接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截; 2 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击 3 通过布隆过滤器实现:把所有用户id放到布隆过滤器中---》请求过来---》去布隆过滤器中检查 id在不在,如果在---》数据肯定有---》继续往后走 ---》如果布隆过滤器中没有---》不是我们的数据---》直接拒绝 ### 缓存击穿 #描述: 缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力 #解决方案: 设置热点数据永远不过期。 ### 缓存雪崩 #描述: 缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。 # 解决方案: 1 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。 2 如果缓存数据库是分布式部署,将热点数据均匀分布在不同得缓存数据库中。 3 设置热点数据永远不过期。
补充 redis的跳跃表:
跳跃表(skiplist)是一种随机化的数据结构是一种可以于平衡树媲美的层次化链表结构——查找、删除、添加等操作都可以在对数期望时间下完成,以下是一个典型的跳跃表例子:
为什么使用跳跃表?
- 性能考虑: 在高并发的情况下,树形结构需要执行一些类似于 rebalance 这样的可能涉及整棵树的操作,相对来说跳跃表的变化只涉及局部 (下面详细说);
- 实现考虑: 在复杂度与红黑树相同的情况下,跳跃表实现起来更简单,看起来也更加直观
但是会存在一些问题 :
插入一个节点之后,就会打乱上下相邻两层链表上节点个数严格的 2:1 的对应关系
为了避免这一问题,它不要求上下相邻两层链表之间的节点个数有严格的对应关系,而是 为每个节点随机出一个层数(level)
Redis 中的跳跃表由 server.h/zskiplistNode
和 server.h/zskiplist
两个结构定义,前者为跳跃表节点,后者则保存了跳跃节点的相关信息,同之前的 集合 list
结构类似,其实只有 zskiplistNode
就可以实现了,但是引入后者是为了更加方便的操作
/* ZSETs use a specialized version of Skiplists */ typedef struct zskiplistNode { // value sds ele; // 分值 double score; // 后退指针 struct zskiplistNode *backward; // 层 struct zskiplistLevel { // 前进指针 struct zskiplistNode *forward; // 跨度 unsigned long span; } level[]; } zskiplistNode; typedef struct zskiplist { // 跳跃表头指针 struct zskiplistNode *header, *tail; // 表中节点的数量 unsigned long length; // 表中层数最大的节点的层数 int level; } zskiplist;
创建跳跃表
具体实现 参考Redis(2)——跳跃表 - 知乎 (zhihu.com)
问题---
-
MySQL索引:
MySQL索引是数据库表中一种特殊的数据结构,它可以帮助快速查询和检索数据。索引的工作原理类似于书籍的目录,它可以让你不用遍历整本书就能快速找到你需要的信息。在MySQL中,常见的索引类型有B-Tree索引(最常用),全文索引,哈希索引等。使用索引可以显著提高查询效率,但也会增加写操作的成本,因为索引也需要维护。 -
最左前缀原则:
最左前缀原则是指在使用复合索引(一个索引包含多个列)时,查询从索引的最左边开始匹配前缀。只有当查询条件中使用了索引最左边的列时,索引才会被利用。例如,如果有一个索引是(A, B, C)
,那么查询条件必须包含列A,索引才会被使用;如果查询条件包含了列A和列B,索引会更有效;如果查询条件只包含列B和列C,那么这个索引就不会被使用。 -
Celery架构:
Celery是一个强大的异步任务队列/作业队列,基于分布式消息传递。它被用来处理异步任务,从而使得应用程序的响应更加快速。Celery架构主要包括以下几个组件:- 任务(Tasks): 被定义为函数,它是异步执行的工作单元。
- 工作者(Workers): 是执行任务的进程。
- 消息代理(Message Broker): 如RabbitMQ或Redis,用于存储发送给Celery的任务。
- 结果后端(Result Backend): 用于存储任务的执行结果,可以是Redis、数据库或其他存储方案。
- 客户端(Clients): 发送任务的程序。
工作流程是这样的:客户端将任务发送到消息代理,工作者监听消息代理,接收任务并执行,执行结果可以被存储在结果后端,以便之后检索。
- Redis主从同步原理:
Redis主从同步是指在Redis主从架构中,从服务器(Slave)复制主服务器(Master)的数据。同步分为全量复制和部分复制:- 全量复制: 当一个新的从服务器连接到主服务器时,或者主从数据同步出现问题需要重新同步时,会进行全量复制。主服务器会生成一个当前数据库快照,并将这个快照发送给从服务器,从服务器接收到快照后载入并开始从这个状态同步数据。
- 部分复制: 当主从连接正常,且只是因为网络等问题导致短暂的数据不一致时,主服务器只会将丢失的数据部分发送给从服务器进行同步。
Redis通过使用复制偏移量和复制积压缓冲区来实现这两种复制机制,确保数据的一致性和完整性。
标签:缓存,redis,celery,cluster,conf,sentinel,7000,节点 From: https://www.cnblogs.com/wzh366/p/18094414