Redis高可用之哨兵模式(第二部分)

news2024/11/19 18:39:29

引言

接上一篇,今天我们来聊一聊Redis的高可用的第二个解决方案:哨兵模式。

一、Redis哨兵模式

哨兵模式(sentinel)是Redis提供的高可用的解决方案之一。由一个或者多个sentinel示例组成的sentinel系统,可以监听任意数量的主服务器,以及这些服务器属下的所有从服务器,并在被监视的主服务进入下线状态时,自动从该主服务器属下的从服务器中选出新的主服务器,对外提供服务。

在这里插入图片描述

1.1 哨兵模式优缺点

  • 优点:在主从复制的基础上实现了主节点的自动故障转移
  • 缺点:部署麻烦、数据可能丢失、扩展麻烦、主从迁移很慢(大概在几十秒),实际项目中大部分用的是集群的解决方案

sentinel本质上是一个运行在特殊模式下的Redis服务器。不过,因为sentinel不存储业务数据,只用来监视数据节点的状态,所以它的代码和普通Redis服务器是不同的。比如:服务的端口和命令表的不同。

sentinel使用的端口及命令表

#define REDIS_SENTINEL_PORT 26379
// src/sentinel.c
struct redisCommand sentinelcmds[] = {
    {"ping",pingCommand,1,"fast @connection",0,NULL,0,0,0,0,0},
	...
    {"info",sentinelInfoCommand,-1,"random @dangerous",0,NULL,0,0,0,0,0},
	...
};

二、如何使用哨兵模式

2.1 启动哨兵模式

使用命令启动sentinel

redis-sentinel /path/sentinel.conf

redis-server /path/sentinel.conf --sentinel

假设有如下配置文件:表示该sentinel监视了两个主服务器master1和master2 ,该sentinel会创建如下图的两个sentinelRedisInstance 实例结构,结构源码及各个字段的功能描述,我们会在源码分析部分详细展开,这里不做赘述:

####################
# master1 configure #
####################
sentinel monitor master1 127.0.0.1 6379 2
sentinel down-after-milliseconds master1 30000
sentinel parallel-sync master1 1
sentinel failover-timeout master1 900000
####################
# master2 configure #
####################
sentinel monitor master2 127.0.0.1 2345 5
sentinel down-after-milliseconds master2 50000
sentinel parallel-sync master2 5
sentinel failover-timeout master2 450000

在这里插入图片描述

2.2 哨兵节点获取被监听对象信息

在加载完配置文件,sentinel获取到要监视的主服务器,会为每个主服务器都创建两个异步的网络连接:命令连接和订阅连接。前者主要用来向主服务器发送命令和接收命令回复,后者用来专门订阅主服务的__sentinel__:hello 频道,这个频道的作用主要用来感知和通知其他sentinel或自身sentinel的存在。

Redis是如何区分一个实例是主服务器、从服务器和sentinel的?
主要看flags字段,SRI_MASTER、SRI_SLAVE、SRI_SENTINEL

2.2.1 获取主服务器信息及下属所有从服务器。

创建完网络连接,sentinel和主服务器就可以通信了。sentinel默认以每10秒一次的频率,通过命令连接想被监视的主服务器发送INFO命令,通过INFO命令的回复获取主服务器的当前信息。这些信息包括两方面:(1)主服务器自身的信息,如自己的run_id 和角色(主/从/sentinel);(2)该主服务器属下所有的从服务器的信息(ip、port 在线状态、复制偏移等);

对于获取的从服务器的信息会被用来更新所属主服务器示例结构的slaves字典,这个字典保存主服务器所有的从服务器信息,字典的key是sentinel自动设置的名字(格式为:ip+port),字典的值为从服务器对应的实例结构。sentinel在分析从服务器的信息时,如果存在,则更新该实例结构,如果从服务器的实例不存在,则说明该从服务器是新发现的,会在slaves字典中为这个从服务器创建新的实例,并且为该从服务器创建两个异步连接:命令连接和订阅连接。在命令连接创建完成后,sentinel默认会以10秒一次的频率向从服务器发送INFO命令,获取从服务器的信息,类似下面的回复:

run_id:32be0699dd27b410fc790da3a6fab17f97899f  //从服务器的运行id
...
# Replication
role:slave                    //从服务器的角色role
master_host:127.0.0.1         //主服务器的ip
master_port:6379              //主服务器的port
master_link_status:up         //主从服务器的连接状态
slave_repl_offset:11887       //从服务器的复制偏移量
slave_priority:100            //从服务器的优先级
# other sectiorns
...
2.2.2 向主服务器和从服务器发送信息

sentinel默认会以每两秒一次的频率,通过命令连接向所有被监视的主、从服务器的__sentinel_:hello频道发送以下命令:

PUBLISH __sentinel:hello "<s_ip>,<s_port>,<s_run_id>,<s_epoch>,<m_name>,<m_ip>,<m_port>,<m_epoch>"

命令说明:
所有以s_开头的参数记录的是sentinel本身的信息;以m_开头的参数表示的是主服务器的信息,如果sentinel监视的是主服务器,那么这些参数记录的就是主服务器的信息,如果监视的是从服务器,这些参数记录的是从服务器正在复制的主服务器的信息。

这个命令有什么用呢?当sentinel与一个主服务器或者从服务器建立起订阅连接后,sentinel就会通过订阅连接,向服务器发送:

SUBSCRIBE _sentinel:hello

也就是说监视了同一主服务器sentinel都订阅了该频道。当一个sentinel往该频道里发送消息是,所有的sentinel都能收到该条消息,包括自身。收到消息的sentinel会根据s_runid来判断是不是自己发出的消息,如果是自己发的就丢弃;如果是别的sentinel发的,更新相应的主服务器实例结构,具体来说就是:收到消息的sentinel会在自己的sentinel状态的masters字典中查找对应的主服务器实例,再在主服务的实例对应的sentinels字典中查找有没有发消息的sentinel的信息,如果有就更新sentinel的实例结构,如果没有说明该sentinel是刚开始监听主服务器的sentinel,为其创建sentinel结构添加到主服务器的sentinels字典中。该字典保存所有监视同一服务器的sentinel。
在这里插入图片描述

sentinel可以通过接收频道的信息来感知其他sentinel的存在,并通过发送频道信息让其他sentinel知道自己的存在。

当sentinel通过频道信息发现了一个新的sentinel时,不仅会在自己的sentinels字典中创建相应的实例,还会创建连向新sentinel的命令连接,而新的sentinel同样会创建连向这个sentinel的命令连接。sentinel之间通过命令连接进行接下来的一系列操作(主客观下线、选举等)。

三、sentinel工作流程

哨兵模式的工作流程可以分为五个步骤:主观下线、客观下线、哨兵选举、从库选主和故障转移

3.1 主观下线

主观下线:就是某个sentinel认为某个实例下线了,就是单纯的“我以为”,还要经过其他的sentinel的认同,才会进入“客观下线”,也就是大家都认为。

sentinel默认会以每秒一次的频率向所有与自己创建了命令连接的实例(主从、其他sentinel)发送PING命令,通过返回值来判断某个实例是否下线。在配置文件中有个参数down-after-milliseconds,这个参数指定sentinel判断一个实例主观下线的时间长度。如果一个实例在down-after-milliseconds毫秒内,连续想sentinel返回了无效回复,sentinel就会修改该实例对应的flags子弹,打开SRI_S_DOWN标识,以此标记这个实例进入主观下线状态。

回复结果:

  • 有效回复: +PONG -LOADING -MASTERDOWN 三种;
  • 无效回复:除有效回复外的所有回复

假设用户配置如下:

sentinel monitor master 127.0.0.1 6379 2
sentinel down-after-milliseconds master 50000

这50000毫秒不仅是sentinel判断master进入主观下线的标准,也会是sentinel判断master属下所有从服务器和所有监视该master的其他sentinel进入主观下线的标准。

注意:多个sentinel设置的主观下线时长可能不同,需要查看具体的配置文件。

3.2 客观下线

当一个sentinel认为一个主服务器为主观下线后,为了确保这个主服务器是不是真的下线了,需要向监视了这个主服务器的其他sentinel询问。当收到足够数量的下线信息后,sentinel会将主服务器判定为客观下线,设置flags的SRI_O_DOWN标识,并准备对主服务器进行故障转移操作。

通过发送 SENTINEL is-mater-down-by-addr 命令询问其他sentinel

SENTINEL is-mater-down-by-addr <ip> <port> <current_epoch> <run_id>

当认为主服务器已经下线状态的sentinel的数量(包括自己),超过sentinel配置中设置的quorum参数的值,那么该sentinel就任务主服务器已经进入客观下线。

// quorum 参数设置
sentinel monitor master 127.0.0.1 6379 2

不同的sentinel判断客观下线的条件也可能不同。

3.3 领头sentinel的选举

选举规则

  • 监视同一个主服务器的任意一个sentinel都有可能成为领头sentinel。
  • 每次选举完领头sentinel后。不论选举是否成功,所有sentinel的配置纪元会自增1。配置纪元实际上就是个计数器,没什么特别的;
  • 在一个配置纪元里,所有的sentinel都有一次能将某个sentinel设置为局部领头sentinel的机会,且机会只有一次,先到先得。
  • 如果在给定时间内,没有一个sentinel被选为领头sentinel,那么各个sentinel会在一段时间后,再次进行选举。配置纪元就是选举的任期。

选举流程

  • 当一个sentinel(源sentinel)向另一个sentinel(目标sentinel)发送 SENTINEL is-master-down-by-addr 命令,并且命令中的参数不是*,而是自己的run_id,表示源sentinel要求目标sentinel将自己设置为它的局部领头sentinel。
  • 目标sentinel在收到SENTINEL is-master-down-by-addr 命令后,回复中的leader_runid 参数和leader_epoch 参数分别记录自己的局部领头sentinel的运行ID和配置纪元;
  • 源sentinel在收到消息后,检查leader_epoch 是不是和自己的配置纪元一致,如果一致,取出 leader_runid 与自己的 run_id 比较,如果一致,表示目标sentinel 同意选自己为局部领头sentinel,如果不一致,说明目标sentinel已经选别的sentinel为局部领头sentinel了
  • 如果某个sentinel被半数以上的sentinel设置为局部领头sentinel,那么这个局部领头sentinel就称为领头sentinel。

3.4 从库选主和故障转移

在选举产生领头sentinel后,领头的sentinel将对已下线的主服务器执行故障转移操作,该操作分为三步:

  1. 在已下线的主服务器属下的从服务器里选一个服务器,将其转为主服务器(SLAVEOF no one)
  2. 让其他从服务器改复制新的主服务器
  3. 将已下线的主服务器设置为新的主服务器的从服务器,当旧的主服务器重新上线时就会称为新的主服务器的从服务器。

在发送SLAVEOF no one命令后,领头的sentinel会以每秒一次的频率发送INFO,检查角色(role)信息,直至变为master,就顺利将从服务器升级为主服务器了。

修改从服务器的复制目标
slaveof <new_master_ip> <new_master_port> 让从服务器复制新的额主服务器。

四、哨兵模式源码分析

sentinelState 定义:

/* Main state. */
struct sentinelState {
    char myid[CONFIG_RUN_ID_SIZE+1]; /* 哨兵的id */
    uint64_t current_epoch;         /* 当前纪元,用来实现故障转移 */
    dict *masters;      // 记录所有被哨兵监视的主服务器的信息,字典的键是主服务器的名字,值是该服务器对应的sentinelRedisInstance服务器实例
                          
    int tilt;           /*是否进入到tilt模式 */
    int running_scripts;    /* 当前运行的脚本的数量*/
    mstime_t tilt_start_time;       /* 进入tilt的时间 */
    mstime_t previous_time;         /* 最后一次执行时间处理器的时间 */
    list *scripts_queue;            /* 保存用户所有要运行的脚本*/
    char *announce_ip;  /* 如果不为NULL,表示与其他sentinel通信的ip地址*/
    int announce_port;  /* 如果不为0,表示与其他sentinel通信的port端口 */
    unsigned long simfailure_flags; /*simulation 失败标志 */
    int deny_scripts_reconfig;  // 是否允许sentinel在运行时通过set xx改变脚本的路径
    // auth 命令使用的用户名和密码,用于验证
    char *sentinel_auth_pass;    /* Password to use for AUTH against other sentinel */
    char *sentinel_auth_user;    /* Username for ACLs AUTH against other sentinel. */
    // 支持域名,前提是设置好DNS
    int resolve_hostnames;       /* Support use of hostnames, assuming DNS is well configured. */
    int announce_hostnames;      /* Announce hostnames instead of IPs when we have them. */
} sentinel;

4.1 什么是TILT?

TITL:因为sentinel依赖本机时间驱动,如果系统时间出问题,或者因为进程阻塞导致的时间函数延迟调用。这时再去参与集群逻辑会出现不正确的决策。因此如果当前时间和上一次执行时间差为负值或者超过2s,该节点会进入TILT模式。

4.2 sentinelRedisInstance结构定义:

每一个sentinelRedisInstance表示一个被sentinel监视的Redis服务器实例。这个实例可以使主服务器、从服务器或者另一个sentinel实例。

typedef struct sentinelRedisInstance {
	// 标识值,记录了实例的类型,以及该实例的当前状态 在sentinel进行故障转移时用到,
    int flags;      /* See SRI_... defines */
    // 实例的名字
	// 主服务器的名字由用户在配置文件中设置
	// 从服务器以及 Sentinel 的名字由 Sentinel 自动设置
	// 格式为 ip:port ,例如 "127.0.0.1:26379"
    char *name;     /* Master name from the point of view of this sentinel. */
    // 实例的运行 ID 服务器初始化自动生成
    char *runid;    /* Run ID of this instance, or unique ID if is a Sentinel.*/
    
    uint64_t config_epoch;  /* 配置纪元,用于实现故障转移 */
    sentinelAddr *addr; /* 实例的地址 ip+port*/
    // 连接状态描述
    instanceLink *link; /* Link to the instance, may be shared for Sentinels. */
    // 最后一次通过发布、订阅频道发送问候信息的时间
    mstime_t last_pub_time;   /* Last time we sent hello via Pub/Sub. */
    // 最后一次从这个sentinel的发布订阅频道收到问候信息的时间。只有当设置了SRI_SENTINEL才会使用
    mstime_t last_hello_time; /* Only used if SRI_SENTINEL is set. Last time
                                 we received a hello from this Sentinel
                                 via Pub/Sub. */
    // 最后一次恢复 is-master-down 命令的时间
    mstime_t last_master_down_reply_time; /* Time of last reply to
                                             SENTINEL is-master-down command. */
    // 
    mstime_t s_down_since_time; /* 主观下线时间. */
    mstime_t o_down_since_time; /* 客观下线时间. */
    mstime_t down_after_period; /* 实例多少毫秒没有响应会被判定为主观下线 */
    // 从实例获取INFO命令回复的时间
    mstime_t info_refresh;  /* Time at which we received INFO output from it. */
    dict *renamed_commands;     /* Commands renamed in this instance:
                                   Sentinel will use the alternative commands
                                   mapped on this table to send things like
                                   SLAVEOF, CONFING, INFO, ... */

    /* Role and the first time we observed it.
     * This is useful in order to delay replacing what the instance reports
     * with our own configuration. We need to always wait some time in order
     * to give a chance to the leader to report the new configuration before
     * we do silly things. */
   	// 实例的角色
    int role_reported;
    mstime_t role_reported_time;
    // 从服务器的主服务器地址最后一次变更的时间
    mstime_t slave_conf_change_time; /* Last time slave master addr changed. */

    /* Master specific. */
    dict *sentinels;    /* 监视了同一个主服务的其他sentinel */
    
    // 如果该服务器时主服务器,则slaves保存该主服务下面所有的从服务器
    dict *slaves;       /* Slaves for this master instance. */

    //判断这个实例为客观下线所需的支持投票数量
    unsigned int quorum;/* Number of sentinels that need to agree on failure. */
    // 在执行故障转移时,可以同时对新的主服务器进行同步的从服务器数量
    int parallel_syncs; /* How many slaves to reconfigure at same time. */
    // 主从复制的用户和密码校验
    char *auth_pass;    /* Password to use for AUTH against master & replica. */
    char *auth_user;    /* Username for ACLs AUTH against master & replica. */

    /* Slave specific. */
    // 主从复制断开的时间
    mstime_t master_link_down_time; /* Slave replication link down time. */
    // 从服务器的优先级
    int slave_priority; /* Slave priority according to its INFO output. */
    int replica_announced; /* Replica announcing according to its INFO output. */
    // 执行故障转移操作时,从服务器发送 SLAVEOF <new-master> 命令的时间
    mstime_t slave_reconf_sent_time; /* Time at which we sent SLAVE OF <new> */
    // 如果该实例是从服务器,则master保存它的主服务器的实例地址
    struct sentinelRedisInstance *master; /* Master instance if it's slave. */
    // INFO 命令的回复中记录的主服务器 IP 和 PORT
    char *slave_master_host;    /* Master host as reported by INFO */
    int slave_master_port;      /* Master port as reported by INFO */
    // INFO 命令中回复的主服务的连接状态
    int slave_master_link_status; /* Master link status as reported by INFO */

	// 从服务器的复制偏移量
    unsigned long long slave_repl_offset; /* Slave replication offset. */
    /* Failover */
    // 如果这是一个主服务器实例,那么 leader 将是负责进行故障转移的 Sentinel 的运行 ID 。
	// 如果这是一个 Sentinel 实例,那么 leader 就是被选举出来的领头 Sentinel 。
	// 这个域只在 Sentinel 实例的 flags 属性的 SRI_MASTER_DOWN 标志处于打开状态时才有效。

    char *leader;       /* If this is a master instance, this is the runid of
                           the Sentinel that should perform the failover. If
                           this is a Sentinel, this is the runid of the Sentinel
                           that this Sentinel voted as leader. */
    // 领头的纪元
    uint64_t leader_epoch; /* Epoch of the 'leader' field. */
    // 当前执行中的故障转移的纪元
    uint64_t failover_epoch; /* Epoch of the currently started failover. */
    // 故障转移操作的当前状态
    int failover_state; /* See SENTINEL_FAILOVER_STATE_* defines. */
    // 故障改变的时间
    mstime_t failover_state_change_time;
    // 最后一次故障转移的时间
    mstime_t failover_start_time;   /* Last failover attempt start time. */
    // SENTINEL failover-timeout <master-name> <ms> 选项的值
	// 刷新故障迁移状态的最大时限
    mstime_t failover_timeout;      /* Max time to refresh failover state. */
    
    mstime_t failover_delay_logged; /* For what failover_start_time value we
                                       logged the failover delay. */
	// 指向被提升为新主服务器的从服务器的指针
    struct sentinelRedisInstance *promoted_slave; /* Promoted slave instance. */
    /* Scripts executed to notify admin or reconfigure clients: when they
     * are set to NULL no script is executed. */
    char *notification_script;
    char *client_reconfig_script;
    sds info; /* cached INFO output */
} sentinelRedisInstance;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/106746.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

(Java高级教程)第二章Java多线程常见面试题-第二节:JUC(java.util.concurrent)

文章目录一&#xff1a;Callable接口二&#xff1a;ReentrantLock三&#xff1a;原子类四&#xff1a;信号量SemaphoreJUC&#xff1a;JUC是java.util.concurrent包的简称&#xff0c;目的就是为了更好的支持高并发任务。让开发者进行多线程编程时减少竞争条件和死锁的问题 一…

智己LS7发布,预售价格区间35-50万元

12月20日&#xff0c;智己首款中大型大五座SUV 智己LS7开启预售。动力配置&#xff1a; •最大零百加速4.5S&#xff1b; •峰值公里425kw&#xff0c;峰值扭矩725Nm&#xff1b; •提供90度和100度电池选项&#xff1b; •最大CLTC续航660km&#xff1b;空间配置&#xff1a; …

06. http协议基础,带你了解网络访问

06. http协议基础&#xff0c;带你了解网络访问 渗透测试学习路径 计算机基础网络基础WEB漏洞渗透测试 渗透测试和WEB安全漏洞的区别&#xff1f; 渗透测试包含WEB安全漏洞 WEB网站只是单一的网站服务&#xff0c;在渗透测试过程中可能不是攻击网站&#xff0c;而是寻找其他…

ElasticSearch全文检索原理及过程

倒排索引 ElasticSearch的搜索引擎中&#xff0c;每个文档都有一个对应的文档 ID&#xff0c;文档内容被表示为一系列关键词的集合。例如文档 1 经过分词&#xff0c;提取了 20 个关键词&#xff0c;每个关键词都会记录它在文档中出现的次数和出现位置。那么&#xff0c;倒排索…

差分---(小明的彩灯)蓝桥杯真题,差分思想很明确的模板

小明的彩灯题目描述暴力解法差分的思路和模板差分解法题目描述 小明拥有 N个彩灯&#xff0c;第 i个彩灯的初始亮度为 ai​。 小明将进行 Q次操作&#xff0c;每次操作可选择一段区间&#xff0c;并使区间内彩灯的亮度 x&#xff08;x可能为负数&#xff09;。 求 Q次操作后…

自动控制原理笔记-传递函数

目录 拉普拉斯反变换&#xff1a; 用拉普拉斯变换求解常微分方程的步骤&#xff1a; 部分分式展开法&#xff1a; 留数法&#xff1a; 零极点图: 传递函数 定义&#xff1a; 传递函数的标准形式&#xff1a; 传递函数的性质&#xff1a; 传递函数的局限性&#xff1a…

SOT23-6封装 小封装 超精简外围PD Sink端取电协议芯片

PD协议&#xff08;USB-PD&#xff09;的全名是USB Power Delivery&#xff0c;是由 USB-IF 组织制定的一种快速充电规范&#xff0c;是目前主流的快充协议之一&#xff0c;USB-PD 快充协议是以 Type-C 接口输出的&#xff0c;我们经常看到的华为笔记本配的Type-C 65W充电器就是…

【C语言】函数栈帧的创建和销毁

目录 1.函数栈帧的含义 概念 要用到的汇编语言的知识 示例 2.理解栈帧 2.1 main函数栈帧的创建 2.2 局部变量的创建 2.3 函数传参 2.4 调用函数 2.5 函数返回 一个.c文件在调用函数的时候&#xff08;包括main 函数&#xff09;&#xff0c;其内存中的栈区有什么变…

Qt之实现工具箱界面程序

最近终于有点空闲时间了&#xff0c;就写写博客&#xff0c;就把上次给客户实现的一个程序开发过程写出来&#xff1b;客户要求的是在主界面上能有几个很好看的按钮&#xff0c;单击各个按钮能弹出不同的应用窗口&#xff0c;如游戏窗口&#xff0c;显示图像窗口等等&#xff0…

pcl 基本操作汇总

目录 PCLVisualizer简单的点云可视化 createViewPort创建视窗 代码 效果 点云视窗上打印文本信息 使用addText 合并多个点云 xyzxyz xyz nxnynz 新建自己的Point类型 点云的刚体变换&#xff08;旋转平移&#xff09; 以下是pcl点云基本操作&#xff0c;后面会慢慢…

C++--数据结构--最小生成树-- Kruskal--Prim--高阶0713

注&#xff1a;本次修改了添加边的一些其他情况可以采用坐标来添加边 void _AddEdge(size_t srci, size_t dsti, const W& w) {_matrix[srci][dsti] w;// 无向图if (Direction false){_matrix[dsti][srci] w;} }void AddEdge(const V& src, const V& dst, const…

【学习笔记03】vue的组件

目录一、组件二、组件的分类&#xff08;一&#xff09;全局组件&#xff08;二&#xff09;局部组件1、为什么vue组件 data函数返回一个对象2、bootstrap的使用三、父组件传值给子组件1、父传子实现进度条2、 props的属性四、子组件传值给父组件五、兄弟组件传值一、组件 可以…

【Javassist】快速入门系列04 使用Javassist更改整个方法体

系列文章目录 01 在方法体的开头或结尾插入代码 02 使用Javassist实现方法执行时间统计 03 使用Javassist实现方法异常处理 04 使用Javassist更改整个方法体 文章目录系列文章目录前言引入Javassist jar包使用Javassist更改整个方法体总结说明前言 上一章我们介绍了使用Javas…

2022全年度白酒十大热门品牌销量榜单

白酒为中国特有的一种蒸馏酒&#xff0c;是世界六大蒸馏酒之一&#xff0c;中国是全球最大的蒸馏酒市场&#xff0c;中国的白酒消费也位列世界烈酒行业领先地位。近几年来&#xff0c;由于市场需求的不断提升及居民的消费升级&#xff0c;高档白酒价格也不断增长&#xff0c;从…

会员管理系统可行性研究

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 1.引言 1.1编写目的 1.2项目背景 1.3定义 1.4参考资料 2.可行性研究前提 2.1要求 2.2目标 2.3条件、假定和限制 2.4决定可行性的因素 3.现有小程序分析 3.1经…

进程-计算机是如何工作的

文章目录冯诺依曼计算机体系组成寄存器和内存编译型语言vs解释型语言进程进程管理进程的状态虚拟地址空间虚拟内存冯诺依曼计算机体系 组成 (1) 输入设备:键盘&#xff0c;鼠标 (2) 输出设备:显示器&#xff0c;打印机 其中硬盘(可做输入、输出) (3) 存储器:内存 (4) CPU 运…

Composing Programs(SICP python版) chap1 笔记

《Composing Programs》(SICP python版) chap1 笔记 持续更新中 在学习 CS61A 2022fall的时候配着看的 文章目录《Composing Programs》(SICP python版) chap1 笔记Chapter 1: Building Abstractions with Functions1.1 Getting Started1.1.1 Programming in Python1.1.2 Insta…

python安装face_recognition

本人使用系统为windows10,python的版本是3.8&#xff0c;在安装face_recognition之前需要安装以下内容&#xff1a; 1.cmake 2.dlib&#xff0c;dlib的安装依赖于cmake 1 安装CMake 1.1 官网下载&#xff1a;CMake 1.2 开始安装CMake: 1.3 验证是否安装成功&#xff1a; 打开…

10 Mysql中各种锁

概述 MySQL中的也存在一些类型的锁&#xff0c;用来保证多个连接同时操作数据时的安全即数据的一致性问题&#xff1b;同时&#xff0c;虽然锁能够解决一些数据的一致性和有效性&#xff0c;但是我们还是要选择合适的锁来降低锁对于并发问题的影响 1. 全局锁 全局锁就是对整…

傻白探索Chiplet,互连技术研究现状(七)

目录 一、串行互连 二、并行互连 三、串行与并行互连的比较 四、互连标准接口 &#xff08;1&#xff09;背景 &#xff08;2&#xff09;UCIe Chiplet的可行性常常受到片间互连的性能、可用性以及功耗和成本问题的限制&#xff0c;各种异构芯片的互连接口和标准的设计在技…