redis主从同步对象模型学习笔记

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: redis主从同步对象模型学习笔记

@TOC

1 淘汰策略

1.1 配置

redis内存是有限制的,当存储的数据超过限制之后,就有一些数据从内存中被淘汰(被删除掉)
在redis.conf中配置,例如 :

  • maxmemory # 配置内存,一般为物理内存的一半,涉及到写时复现,具体看面的章节
  • maxmemory-policy noeviction # 选择LRU,LFU,TTL
  • maxmemory-samples 5 # 最大样本数,在样本中运行LRU,LFU,TTL等策略
  • maxmemory-eviction-tenacity # 参数指定内存驱逐韧性
    。。。

    1.2 哪些数据将会被淘汰呢?

    1.2.1 过期key中的

    保存在==redisDb dict *expires==
/* Redis database representation. There are multiple databases identified
 * by integers from 0 (the default database) up to the max configured
 * database. The database number is the 'id' field in the structure. */
typedef struct redisDb {
   
   
    dict *dict;                 /* The keyspace for this DB */
    dict *expires;              /* Timeout of keys with a timeout set */
    dict *blocking_keys;        /* Keys with clients waiting for data (BLPOP)*/
    dict *ready_keys;           /* Blocked keys that received a PUSH */
    dict *watched_keys;         /* WATCHED keys for MULTI/EXEC CAS */
    int id;                     /* Database ID */
    long long avg_ttl;          /* Average TTL, just for stats */
    unsigned long expires_cursor; /* Cursor of the active expire cycle. */
    list *defrag_later;         /* List of key names to attempt to defrag one by one, gradually. */
    clusterSlotToKeyMapping *slots_to_keys; /* Array of slots to keys. Only used in cluster mode (db 0). */
} redisDb;

用到的策略有以下4种:

  • LRU Least recent use 最长时间没有使用的淘汰
  • LFU Least Frequently Used 最少使用次数的淘汰,数据量大的时候,也是要先采用随机采样的方式。
  • TTL 最近要过期的 TTL(Time-to-Live)是一个网络术语,指数据包或者消息在网络中允许存在的时间长度。
  • 随机策略 # 当内存达到最大后,随机淘汰
    这些策略怎么配置呢?要么是配置定的阀值,抽取一定量的样本(数据量比较大的时候)。
    这里着重了解一下LRU,LFU,它们对应的代码:(lru用24字节表示,当它表示LRU的时候用的是24个字节;当它表示LFU时,前8个字节表示最少使用次数,后16个字面表示时间)
    #define LRU_BITS 24
    typedef struct redisObject {
         
         
      unsigned type:4;
      unsigned encoding:4;
      unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
                              * LFU data (least significant 8 bits frequency
                              * and most significant 16 bits access time). */
      int refcount;
      void *ptr;
    } robj;
    
    eg: 通过object命令来演示lru
127.0.0.1:6379> object help
 1) OBJECT <subcommand> [<arg> [value] [opt] ...]. Subcommands are:
 2) ENCODING <key>
 3)     Return the kind of internal representation used in order to store the value
 4)     associated with a <key>.
 5) FREQ <key>
 6)     Return the access frequency index of the <key>. The returned integer is
 7)     proportional to the logarithm of the recent access frequency of the key.
 8) IDLETIME <key>
 9)     Return the idle time of the <key>, that is the approximated number of
10)     seconds elapsed since the last access to the key.
11) REFCOUNT <key>
12)     Return the number of references of the value associated with the specified
13)     <key>.
14) HELP

先设置key为hello,再查看key存在的时间,发现是38秒。这个38秒就是存在lru中的

127.0.0.1:6379> set key hello
OK
127.0.0.1:6379> object idletime key
(integer) 38

1.2.2 所有的key

同上一小节1.2.1,只是减少了TTL策略

  • LRU Least recent use 最长时间没有使用的淘汰
  • LFU Least Frequently Used 最少使用次数的淘汰
  • 随机策略 # 当内存达到最大后,随机淘汰

1.2.3 禁止淘汰

no-eviction:当内存达到最大后,新数据不能写入,会报错

2 持久化

2.1 背景

2.1.1 概念

保存在内存中的数据,在关机后,数据会消失,如果在关机、断电前将数据保存在磁盘中,
重新开机后再把数据从磁盘读入到内存中,这就是持久化。
对于redis就是:内存数据库,redis重启需要加载回原来的数据。

2.1.2 fork进程写时复制机制

  • fork子进程时将父进程的页表复制,两个页表一样,它们都映射到同一块物理内存
      此时如果要修改内存数据?与子进程之间不就冲突了吗?===> 解决:复制页表的时候,会把页表的每一项都设置为只读状态,父进程依然对外提供服务。    
    
  • 因此父进程对数据进行修改时,因为页表只读,写保护中断,从而触发缺页异常,进而进行物理内存的复制(相关页的)
  • 父进程的页表修改可读写状态,然后指向新的物理内存
  • 子进程的页表指向原来的物理内存
  • 在发生写操作的时候,系统才会去复制物理内存
  • 避免物理内存的复制时间过长导致父进程长时间阻塞

优点:

  • 有独立的运行环境去持久化。
  • 只要是父进程没有修改的内存页,子进程与父进程所对应的数据还是一样的。

    2.1.3 大key

  • kv 中 v 如果占用大量空间
    比如v是hash、zset,里面存储了大量的元素。

    2.2 redis持久化的方式

    2.2.1 aof

    aof 基于redis协议,有修改就在当前进程中追加到文件末尾(append only file)
      通过系统调用write将数据写到page_buf,然后通过手动sync/fsync 刷到磁盘,或者内核刷到磁盘。
    
  • always 每一个写的命令,持久化一次 在主线程(可能会阻塞) redis.conf: appendonly = yes
  • every_sec 在bio_aof_fsync 线程进行(不阻塞主线程)
  • no 不用aof持久化的方式,即redis.conf: appendonly no
    相关的设置===>redis.conf中查找:appendonly appendfilename appenddirname appendfsync
    auto-aof-rewrite-percentage auto-aof-rewrite-min-size

比如下面的两条命令

aof-
127.0.0.1:6379> set tt2 2
OK
127.0.0.1:6379> set ttt3 3
OK

对应的保存在appendfilename "appendonly.aof"里面的数据是

*3
$3
set
$3
tt2
$1
2
*3
$3
set
$4
ttt3
$1
3

redis重启恢复的时候,就可以按照上面redis协议存储的数据来恢复。

2.2.2 aof-rewrite

相对于aof,可以避免重复的命令, eg:
set key1 1
set key1 2
这两条命令即可以优化为set key1 2
工作原理:fork进程,根据内存数据生成aof文件,==避免同一个key的历史冗余数据==,
在重写aof期间,对redis的写操作会记录到重写缓冲区,当重写aof结束后,附加到aof文件的末尾。

2.2.3 rdb

  • rdb 通过fork子进程持久化,基于内存所有==数据对象编码==直接持久化
  • rrdb-aof 混用,通过fork子进程,根据内存数据生成rdb文件;在rdb持久化期间,
    对redis的写操作会记录到重写缓冲区,当rdb持久化结束后,附加到aof文件末尾。

2.3 redis持久方案的优缺点

  • aof
    优点:数据可靠,丢失较少;持久化过程代价较低
    缺点:aof文件过大,数据恢复慢

  • rdb
    优点:rdb 文件小,数据恢复快
    缺点: 数据丢失较多,持久化过程代价较高

  • 混合持久化
    从上面知道,rdb 文件小且加载快但丢失多,aof 文件大且加载慢但丢失少;
    混合持久化是吸取 rdb 和 aof 两者优点的一种持久化方案;
    aof-rewrite 的时候实际持久化的内容是 rdb,等持久化后,持久化期间修改的数据以 aof 的形式附加到文件的尾部;
    混合持久化实际上是在 aof-rewrite 基础上进行优化;所以需要先开启 aof-rewrite;
    配置:

    # 开启 aof
    appendonly yes
    # 开启 aof复写
    auto-aof-rewrite-percentage 100
    auto-aof-rewrite-min-size 64mb
    # 开启 混合持久化
    aof-use-rdb-preamble yes
    # 关闭 rdb
    save ""
    # save 3600 1
    # save 300 100
    # save 60 10000
    

    2.4 大key对持久化的影响

  • fsync压力大,数据刷磁盘时间长
  • fork的时间长,fork的时候,写时复制造成的持久化时间长
    时间长,断电、宕机的影响就会非常的大。

    3 高可用性

    3.1 背景

    工作中重要的服务器一般会有异地备份,如果某个一个服务器坏了,还可以从异地服务器中去恢复。
    核心概念:
    == 主从复制 是高可用性的基础 ==
    1 解决单点故障的问题
    2 高可用方案的基础

3.2 主从复制

在这里插入图片描述

  • redis采用异步复制,主从之间存在数据不一样的情况,一般都是从服务器发起建立连接的请求,同步数据的请求。
    可以是全量数据同步,也可以是增量数据同步,可能带来数据丢失。

  • runid : 标识身份,从数据库须持有与主数据库有相同的runid。

  • 环形缓冲区:主数据中有一个环形缓冲区记录同步状态。某个从数据库发送“复制偏移量”到主数据库,
    如果它在环形缓冲区,可以进行正常的同步数据,否则,需要全量同步数据。
  • 主从复制不能保证高可用(合理时间内有合理的回应),解决了闪电战故障的问题
  • 主节点宕机,整体系统没有什么可用性。从而引出下一节,主redis可被取代的哨兵模式。

    3.3 哨兵模式

    稍作了解,原理图如下:
    不用
    client与哨兵系统建立连接,监听switch-master 主从切换。
    通过哨兵系统结点sentinel 不停的探测主redis,与从redis,当主redis宕机后,会分配一个从redis来当redis。
    相当于网络中的探活机制
  • 网络协议栈 tcp-keepalive
  • 应用层 心跳包/ ping/pong(redis) 看网络主循环是不是在运行,应用层有没有死机
    当主redis宕机时,哨兵系统可以根据“复制偏移量”谁大谁最新,确立新的主redis。

缺点:架构太复杂,部署麻烦,也不能避免数据丢失。主从切换花的时间需要几十秒,时间较长。

3.4 cluster 集群

可护展,去中心化的集群
图片来源于网络
图片来源于网络
图中有3个主节点,每个主节点各带2个从节点。

  • 三个主节点相当于哈希数组的3个槽位,分别用来存储某一个范围的数据(类似于分布式一致性hash),因此主节点存储的数据是不一样的,去中心化的。
  • 可以从任何一个节点去进入集群。
  • 可以扩容,增加一个主节点,再给它一个hash槽位,分配存储一定范围的数据,可以从之前的主节点的数据迁移一部分过去,之前主节点的数据范围也需要改变。

3.5 hiredis-cluster 安装编译

git clone https://github.com/Nordix/hirediscluster.
git
cd hiredis-cluster
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -
DENABLE_SSL=ON ..
make
sudo make install
sudo ldconfig

智能创建集群

redis-cli --cluster help
# --cluster-replicas 后面对应的参数 为 一主对应几个从数据库
redis-cli --cluster create host1:port1 ...
hostN:portN --cluster-replicas <arg>
redis-cli --cluster create 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 127.0.0.1:7006 --cluster-replicas 1

具体的实验部分,后续更新。。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
20天前
|
存储 NoSQL Redis
08- 什么是 Redis 主从同步?
Redis主从同步是种数据备份机制,Slave从Master获取全量数据,之后持续接收增量更新。全量复制阶段包括Slave请求同步、Master拒绝增量并发送RDB到Slave、Slave加载RDB。增量复制阶段,Master使用repl_backlog存储命令并发送给Slave,Slave执行这些命令以保持与Master同步。该机制确保主从数据一致性,支持多个Slave和一个Master。
29 0
|
4月前
|
NoSQL Linux Redis
Redis原理之网络模型笔记
Redis采用单线程模型,这意味着一个Redis服务器在任何时刻都只会处理一个请求。Redis的网络模型涉及到阻塞I/O(Blocking I/O)、非阻塞I/O(Non-blocking I/O)、I/O多路复用(I/O Multiplexing)、信号驱动I/O(Signal-driven I/O)以及异步I/O(Asynchronous I/O)。
|
2月前
|
存储 NoSQL 算法
【Redis技术进阶之路】「底层源码解析」揭秘高效存储模型与数据结构底层实现(字典)(二)
【Redis技术进阶之路】「底层源码解析」揭秘高效存储模型与数据结构底层实现(字典)
49 0
|
5天前
|
存储 NoSQL Linux
Redis入门到通关之Redis5种网络模型详解
Redis入门到通关之Redis5种网络模型详解
21 1
|
2月前
|
存储 NoSQL Redis
作者推荐 |【Redis技术进阶之路】「原理系列开篇」揭秘高效存储模型与数据结构底层实现(SDS)(三)
作者推荐 |【Redis技术进阶之路】「原理系列开篇」揭秘高效存储模型与数据结构底层实现(SDS)
36 0
|
2月前
|
NoSQL Redis
[Redis]——主从同步原理(全量同步、增量同步)
[Redis]——主从同步原理(全量同步、增量同步)
114 2
|
3月前
|
存储 NoSQL Redis
Redis淘汰策略、持久化、主从同步与对象模型
Redis淘汰策略、持久化、主从同步与对象模型
90 0
|
4月前
|
缓存 NoSQL 安全
Redis 新特性篇:多线程模型解读
Redis 新特性篇:多线程模型解读
50 5
|
4月前
|
存储 缓存 NoSQL
Redis 数据结构+线程模型+持久化+内存淘汰+分布式
Redis 数据结构+线程模型+持久化+内存淘汰+分布式
311 0
|
20天前
|
存储 NoSQL 算法
09- Redis分片集群中数据是怎么存储和读取的 ?
Redis分片集群使用哈希槽分区算法,包含16384个槽(0-16383)。数据存储时,通过CRC16算法对key计算并模16383,确定槽位,进而分配至对应节点。读取时,根据槽位找到相应节点直接操作。
54 12