当前位置: 首页 > news >正文

Redis(5):哨兵

一、作用和架构

1. 作用

  在介绍哨兵之前,首先从宏观角度回顾一下Redis实现高可用相关的技术。它们包括:持久化、复制、哨兵和集群,其主要作用和解决的问题是:
1)持久化:持久化是最简单的高可用方法(有时甚至不被归为高可用的手段),主要作用是数据备份,即将数据存储在硬盘,保证数据不会因进程退出而丢失。
2)复制:复制是高可用Redis的基础,哨兵和集群都是在复制基础上实现高可用的。复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。缺陷:故障恢复无法自动化;写操作无法负载均衡;存储能力受到单机的限制。
3)哨兵:在复制的基础上,哨兵实现了自动化的故障恢复。缺陷:写操作无法负载均衡;存储能力受到单机的限制。
4)集群:通过集群,Redis解决了写操作无法负载均衡,以及存储能力受到单机限制的问题,实现了较为完善的高可用方案。
  
  下面说回哨兵。
  Redis Sentinel,即Redis哨兵,在Redis 2.8版本开始引入。哨兵的核心功能是主节点的自动故障转移。下面是Redis官方文档对于哨兵功能的描述:
1)监控(Monitoring):哨兵会不断地检查主节点和从节点是否运作正常。
2)自动故障转移(Automatic failover):当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点。
3)配置提供者(Configuration provider):客户端在初始化时,通过连接哨兵来获得当前Redis服务的主节点地址。
4)通知(Notification):哨兵可以将故障转移的结果发送给客户端。
  其中,监控和自动故障转移功能,使得哨兵可以及时发现主节点故障并完成转移;而配置提供者和通知功能,则需要在与客户端的交互中才能体现。
  这里对“客户端”一词在文章中的用法做一个说明:在前面的文章中,只要通过API访问redis服务器,都会称作客户端,包括redis-cli、Java客户端Jedis等;为了便于区分说明,本文中的客户端并不包括redis-cli,而是比redis-cli更加复杂:redis-cli使用的是redis提供的底层接口,而客户端则对这些接口、功能进行了封装,以便充分利用哨兵的配置提供者和通知功能。

2. 架构

典型的哨兵架构图如下所示:

  • 哨兵节点:哨兵系统由一个或多个哨兵节点组成,哨兵节点是特殊的redis节点,不存储数据。
  • 数据节点:主节点和从节点都是数据节点。

二、部署

  这一部分将部署一个简单的哨兵系统,包含1个主节点、2个从节点和3个哨兵节点。方便起见:所有这些节点都部署在一台机器上(局域网IP:192.168.92.128),使用端口号区分;节点的配置尽可能简化。

1. 部署主从节点

  哨兵系统中的主从节点,与普通的主从节点配置是一样的,并不需要做任何额外配置。下面分别是主节点(port=6379)和2个从节点(port=6380/6381)的配置文件,配置都比较简单,不再详述。

#redis-6379.conf
port 6379
daemonize yes
logfile "6379.log"
dbfilename "dump-6379.rdb"#redis-6380.conf
port 6380
daemonize yes
logfile "6380.log"
dbfilename "dump-6380.rdb"
slaveof 192.168.92.128 6379#redis-6381.conf
port 6381
daemonize yes
logfile "6381.log"
dbfilename "dump-6381.rdb"
slaveof 192.168.92.128 6379

配置完成后,依次启动主节点和从节点:

redis-server redis-6379.conf 
redis-server redis-6380.conf 
redis-server redis-6381.conf

节点启动后,连接主节点查看主从状态是否正常,如下图所示:

2. 部署哨兵节点

  哨兵节点本质上是特殊的Redis节点。
  3个哨兵节点的配置几乎是完全一样的,主要区别在于端口号的不同(26379/26380/26381),下面以26379节点为例介绍节点的配置和启动方式;配置部分尽量简化,更多配置会在后面介绍。

#sentinel-26379.conf
port 26379
daemonize yes
logfile "26379.log"
sentinel monitor mymaster 192.168.92.128 6379 2

  其中,sentinel monitor mymaster 192.168.92.128 6379 2配置的含义是:该哨兵节点监控192.168.92.128:6379这个主节点,该主节点的名称是mymaster,最后的2的含义与主节点的故障判定有关:至少需要2个哨兵节点同意,才能判定主节点故障并进行故障转移。
  哨兵节点的启动有两种方式,二者作用是完全相同的:

redis-sentinel sentinel-26379.conf 
redis-server sentinel-26379.conf --sentinel 

  按照上述方式配置和启动之后,整个哨兵系统就启动完毕了。可以通过redis-cli连接哨兵节点进行验证,如下图所示:可以看出26379哨兵节点已经在监控mymaster主节点(即192.168.92.128:6379),并发现了其2个从节点和另外2个哨兵节点。

  此时如果查看哨兵节点的配置文件,会发现一些变化,以26379为例:

  其中,dir只是显式声明了数据和日志所在的目录(在哨兵语境下只有日志);known-slave和known-sentinel显示哨兵已经发现了从节点和其他哨兵;带有epoch的参数与配置纪元有关(配置纪元是一个从0开始的计数器,每进行一次领导者哨兵选举,都会+1;领导者哨兵选举是故障转移阶段的一个操作,在后文原理部分会介绍)。

3. 演示故障转移

  哨兵的4个作用中,配置提供者和通知需要客户端的配合,本文将在下一章介绍客户端访问哨兵系统的方法时详细介绍。这一小节将演示当主节点发生故障时,哨兵的监控和自动故障转移功能。
(1)首先,使用kill命令杀掉主节点:

(2)如果此时立即在哨兵节点中使用info Sentinel命令查看,会发现主节点还没有切换过来,因为哨兵发现主节点故障并转移,需要一段时间。

(3)一段时间以后,再次在哨兵节点中执行info Sentinel查看,发现主节点已经切换成6380节点。

  但是同时可以发现,哨兵节点认为新的主节点仍然有2个从节点,这是因为哨兵在将6380切换成主节点的同时,将6379节点置为其从节点;虽然6379从节点已经挂掉,但是由于哨兵并不会对从节点进行客观下线(其含义将在原理部分介绍),因此认为该从节点一直存在。当6379节点重新启动后,会自动变成6380节点的从节点。下面验证一下。
(4)重启6379节点:可以看到6379节点成为了6380节点的从节点。

(5)在故障转移阶段,哨兵和主从节点的配置文件都会被改写。
对于主从节点,主要是slaveof配置的变化:新的主节点没有了slaveof配置,其从节点则slaveof新的主节点。
对于哨兵节点,除了主从节点信息的变化,纪元(epoch)也会变化,下图中可以看到纪元相关的参数都+1了。

4. 总结

  哨兵系统的搭建过程,有几点需要注意:
(1)哨兵系统中的主从节点,与普通的主从节点并没有什么区别,故障发现和转移是由哨兵来控制和完成的。
(2)哨兵节点本质上是redis节点。
(3)每个哨兵节点,只需要配置监控主节点,便可以自动发现其他的哨兵节点和从节点。
(4)在哨兵节点启动和故障转移阶段,各个节点的配置文件会被重写(config rewrite)。
(5)本章的例子中,一个哨兵只监控了一个主节点;实际上,一个哨兵可以监控多个主节点,通过配置多条sentinel monitor即可实现。

三、客户端访问哨兵系统

  上一小节演示了哨兵的两大作用:监控和自动故障转移,本小节则结合客户端演示哨兵的另外两个作用:配置提供者和通知。

1. 代码示例

  在介绍客户端的原理之前,先以Java客户端Jedis为例,演示一下使用方法:下面代码可以连接我们刚刚搭建的哨兵系统,并进行各种读写操作(代码中只演示如何连接哨兵,异常处理、资源关闭等未考虑)。

blic static void testSentinel() throws Exception {String masterName = "mymaster";Set<String> sentinels = new HashSet<>();sentinels.add("192.168.92.128:26379");sentinels.add("192.168.92.128:26380");sentinels.add("192.168.92.128:26381");JedisSentinelPool pool = new JedisSentinelPool(masterName, sentinels); //初始化过程做了很多工作Jedis jedis = pool.getResource();jedis.set("key1", "value1");pool.close();
}

2. 客户端原理

  Jedis客户端对哨兵提供了很好的支持。如上述代码所示,我们只需要向Jedis提供哨兵节点集合和masterName,构造JedisSentinelPool对象;然后便可以像使用普通redis连接池一样来使用了:通过pool.getResource()获取连接,执行具体的命令。
  在整个过程中,我们的代码不需要显式的指定主节点的地址,就可以连接到主节点;代码中对故障转移没有任何体现,就可以在哨兵完成故障转移后自动的切换主节点。之所以可以做到这一点,是因为在JedisSentinelPool的构造器中,进行了相关的工作;主要包括以下两点:
(1)遍历哨兵节点,获取主节点信息:遍历哨兵节点,通过其中一个哨兵节点+masterName获得主节点的信息;该功能是通过调用哨兵节点的sentinel get-master-addr-by-name命令实现,该命令示例如下

一旦获得主节点信息,停止遍历(因此一般来说遍历到第一个哨兵节点,循环就停止了)。
(2)增加对哨兵的监听:这样当发生故障转移时,客户端便可以收到哨兵的通知,从而完成主节点的切换。具体做法是:利用redis提供的发布订阅功能,为每一个哨兵节点开启一个单独的线程,订阅哨兵节点的+switch-master频道,当收到消息时,重新初始化连接池。

3. 总结

  通过客户端原理的介绍,可以加深对哨兵功能的理解:
(1)配置提供者:客户端可以通过哨兵节点+masterName获取主节点信息,在这里哨兵起到的作用就是配置提供者。
  需要注意的是,哨兵只是配置提供者,而不是代理。二者的区别在于:如果是配置提供者,客户端在通过哨兵获得主节点信息后,会直接建立到主节点的连接,后续的请求(如set/get)会直接发向主节点;如果是代理,客户端的每一次请求都会发向哨兵,哨兵再通过主节点处理请求。
  举一个例子可以很好的理解哨兵的作用是配置提供者,而不是代理。在前面部署的哨兵系统中,将哨兵节点的配置文件进行如下修改:

sentinel monitor mymaster 192.168.92.128 6379 2
改为
sentinel monitor mymaster 127.0.0.1 6379 2

  然后,将前述客户端代码在局域网的另外一台机器上运行,会发现客户端无法连接主节点;这是因为哨兵作为配置提供者,客户端通过它查询到主节点的地址为127.0.0.1:6379,客户端会向127.0.0.1:6379建立redis连接,自然无法连接。如果哨兵是代理,这个问题就不会出现了。
(2)通知:哨兵节点在故障转移完成后,会将新的主节点信息发送给客户端,以便客户端及时切换主节点。

四、基本原理

  前面介绍了哨兵部署、使用的基本方法,本部分介绍哨兵实现的基本原理。

1. 哨兵节点支持的命令

  哨兵节点作为运行在特殊模式下的redis节点,其支持的命令与普通的redis节点不同。在运维中,我们可以通过这些命令查询或修改哨兵系统;不过更重要的是,哨兵系统要实现故障发现、故障转移等各种功能,离不开哨兵节点之间的通信,而通信的很大一部分是通过哨兵节点支持的命令来实现的。下面介绍哨兵节点支持的主要命令。

  • (1)基础查询:通过这些命令,可以查询哨兵系统的拓扑结构、节点信息、配置信息等。

    • info sentinel:获取监控的所有主节点的基本信息
    • sentinel masters:获取监控的所有主节点的详细信息
    • sentinel master mymaster:获取监控的主节点mymaster的详细信息
    • sentinel slaves mymaster:获取监控的主节点mymaster的从节点的详细信息
    • sentinel sentinels mymaster:获取监控的主节点mymaster的哨兵节点的详细信息
    • sentinel get-master-addr-by-name mymaster:获取监控的主节点mymaster的地址信息,前文已有介绍
    • sentinel is-master-down-by-addr:哨兵节点之间可以通过该命令询问主节点是否下线,从而对是否客观下线做出判断
  • (2)增加/移除对主节点的监控

    • sentinel monitor mymaster2 192.168.92.128 16379 2:与部署哨兵节点时配置文件中的sentinel monitor功能完全一样,不再详述
    • sentinel remove mymaster2:取消当前哨兵节点对主节点mymaster2的监控
  • (3)强制故障转移

    • sentinel failover mymaster:该命令可以强制对mymaster执行故障转移,即便当前的主节点运行完好;例如,如果当前主节点所在机器即将报废,便可以提前通过failover命令进行故障转移。

2. 基本原理

  • (1)定时任务:每个哨兵节点维护了3个定时任务。定时任务的功能分别如下:通过向主从节点发送info命令获取最新的主从结构;通过发布订阅功能获取其他哨兵节点的信息;通过向其他节点发送ping命令进行心跳检测,判断是否下线。
  • (2)主观下线:在心跳检测的定时任务中,如果其他节点超过一定时间没有回复,哨兵节点就会将其进行主观下线。顾名思义,主观下线的意思是一个哨兵节点“主观地”判断下线;与主观下线相对应的是客观下线。
  • (3)客观下线:哨兵节点在对主节点进行主观下线后,会通过sentinel is-master-down-by-addr命令询问其他哨兵节点该主节点的状态;如果判断主节点下线的哨兵数量达到一定数值,则对该主节点进行客观下线。
    需要特别注意的是,客观下线是主节点才有的概念;如果从节点和哨兵节点发生故障,被哨兵主观下线后,不会再有后续的客观下线和故障转移操作。
  • (4)选举领导者哨兵节点:当主节点被判断客观下线以后,各个哨兵节点会进行协商,选举出一个领导者哨兵节点,并由该领导者节点对其进行故障转移操作。
      监视该主节点的所有哨兵都有可能被选为领导者,选举使用的算法是Raft算法;Raft算法的基本思路是先到先得:即在一轮选举中,哨兵A向B发送成为领导者的申请,如果B没有同意过其他哨兵,则会同意A成为领导者。选举的具体过程这里不做详细描述,一般来说,哨兵选择的过程很快,谁先完成客观下线,一般就能成为领导者。
  • (5)故障转移:选举出的领导者哨兵,开始进行故障转移操作,该操作大体可以分为3个步骤:
    • 在从节点中选择新的主节点:选择的原则是,首先过滤掉不健康的从节点;然后选择优先级最高的从节点(由slave-priority指定);如果优先级无法区分,则选择复制偏移量最大的从节点;如果仍无法区分,则选择runid最小的从节点。
    • 更新主从状态:通过slaveof no one命令,让选出来的从节点成为主节点;并通过slaveof命令让其他节点成为其从节点。
    • 将已经下线的主节点(即6379)设置为新的主节点的从节点,当6379重新上线后,它会成为新的主节点的从节点。

  通过上述几个关键概念,可以基本了解哨兵的工作原理。为了更形象的说明,下图展示了领导者哨兵节点的日志,包括从节点启动到完成故障转移。

五、配置与实践建议

1. 配置

  下面介绍与哨兵相关的几个配置。
(1) sentinel monitor {masterName}{masterIp} {masterPort} {quorum}
  sentinel monitor是哨兵最核心的配置,在前文讲述部署哨兵节点时已说明,其中:masterName指定了主节点名称,masterIp和masterPort指定了主节点地址,quorum是判断主节点客观下线的哨兵数量阈值:当判定主节点下线的哨兵数量达到quorum时,对主节点进行客观下线。建议取值为哨兵数量的一半加1。
(2) sentinel down-after-milliseconds {masterName} {time}
  sentinel down-after-milliseconds与主观下线的判断有关:哨兵使用ping命令对其他节点进行心跳检测,如果其他节点超过down- after-milliseconds配置的时间没有回复,哨兵就会将其进行主观下线。该配置对主节点、从节点和哨兵节点的主观下线判定都有效。
  down-after-milliseconds的默认值是30000,即30s;可以根据不同的网络环境和应用要求来调整:值越大,对主观下线的判定会越宽松,好处是误判的可能性小,坏处是故障发现和故障转移的时间变长,客户端等待的时间也会变长。例如,如果应用对可用性要求较高,则可以将值适当调小,当故障发生时尽快完成转移;如果网络环境相对较差,可以适当提高该阈值,避免频繁误判。
(3)sentinel parallel-syncs {masterName} {number}
  sentinel parallel-syncs与故障转移之后从节点的复制有关:它规定了每次向新的主节点发起复制操作的从节点个数。例如,假设主节点切换完成之后,有3个从节点要向新的主节点发起复制;如果parallel-syncs=1,则从节点会一个一个开始复制;如果parallel-syncs=3,则3个从节点会一起开始复制。
  parallel-syncs取值越大,从节点完成复制的时间越快,但是对主节点的网络负载、硬盘负载造成的压力也越大;应根据实际情况设置。例如,如果主节点的负载较低,而从节点对服务可用的要求较高,可以适量增加parallel-syncs取值。parallel-syncs的默认值是1。
(4) sentinel failover-timeout {masterName}{time}
  sentinel failover-timeout与故障转移超时的判断有关,但是该参数不是用来判断整个故障转移阶段的超时,而是其几个子阶段的超时,例如如果主节点晋升从节点时间超过timeout,或从节点向新的主节点发起复制操作的时间(不包括复制数据的时间)超过timeout,都会导致故障转移超时失败。
  failover-timeout的默认值是180000,即180s;如果超时,则下一次该值会变为原来的2倍。
(5)除上述几个参数外,还有一些其他参数,如安全验证相关的参数,这里不做介绍。

2. 实践建议

(1)哨兵节点的数量应不止一个,一方面增加哨兵节点的冗余,避免哨兵本身成为高可用的瓶颈;另一方面减少对下线的误判。此外,这些不同的哨兵节点应部署在不同的物理机上。
(2)哨兵节点的数量应该是奇数,便于哨兵通过投票做出“决策”:领导者选举的决策、客观下线的决策等。
(3)各个哨兵节点的配置应一致,包括硬件、参数等;此外,所有节点都应该使用ntp或类似服务,保证时间准确、一致。
(4)哨兵的配置提供者和通知客户端功能,需要客户端的支持才能实现,如前文所说的Jedis;如果开发者使用的库未提供相应支持,则可能需要开发者自己实现。
(5)当哨兵系统中的节点在docker(或其他可能进行端口映射的软件)中部署时,应特别注意端口映射可能会导致哨兵系统无法正常工作,因为哨兵的工作基于与其他节点的通信,而docker的端口映射可能导致哨兵无法连接到其他节点。例如,哨兵之间互相发现,依赖于它们对外宣称的IP和port,如果某个哨兵A部署在做了端口映射的docker中,那么其他哨兵使用A宣称的port无法连接到A。

六、总结

  本文首先介绍了哨兵的作用:监控、故障转移、配置提供者和通知;然后讲述了哨兵系统的部署方法,以及通过客户端访问哨兵系统的方法;再然后简要说明了哨兵实现的基本原理;最后给出了关于哨兵实践的一些建议。
  在主从复制的基础上,哨兵引入了主节点的自动故障转移,进一步提高了Redis的高可用性;但是哨兵的缺陷同样很明显:哨兵无法对从节点进行自动故障转移,在读写分离场景下,从节点故障会导致读服务不可用,需要我们对从节点做额外的监控、切换操作。
  此外,哨兵仍然没有解决写操作无法负载均衡、及存储能力受到单机限制的问题;这些问题的解决需要使用集群,我将在后面的文章中介绍,欢迎关注。

参考文献

深入学习Redis(4):哨兵 - cnblog

相关文章:

Redis(5):哨兵

一、作用和架构 1. 作用 在介绍哨兵之前&#xff0c;首先从宏观角度回顾一下Redis实现高可用相关的技术。它们包括&#xff1a;持久化、复制、哨兵和集群&#xff0c;其主要作用和解决的问题是&#xff1a; 1&#xff09;持久化&#xff1a;持久化是最简单的高可用方法(有时甚…...

【人工智能】Transformers之Pipeline(二十五):图片特征抽取(image-feature-extraction)

​​​​​​​ 目录 一、引言 二、图片特征抽取&#xff08;image-feature-extraction&#xff09; 2.1 概述 2.2 google/ViT 2.3 pipeline参数 2.3.1 pipeline对象实例化参数 2.3.2 pipeline对象使用参数 2.4 pipeline实战 2.5 模型排名 三、总结 一、引言 pi…...

podman 源码 5.3.1编译

1. 构建环境 在麒麟V10服务器操作系统上构建&#xff1a;Kylin-Server-V10-GFB-Release-2204-Build03-ARM64.iso。由于只是编译 podman 源码&#xff0c;没必要特地在物理机或服务上安装一个这样的操作系统&#xff0c;故采用在虚拟机里验证。 2. 安装依赖 参考资料&#xf…...

矩阵重新排列——rot90函数

通过 r o t 90 rot90 rot90函数可以将矩阵进行旋转 用法&#xff1a; r o t 90 ( a , k ) rot90(a,k) rot90(a,k)将矩阵 a a a按逆时针方向旋转 k 9 0 ∘ k\times90^\circ k90∘...

Leetcode 51 N Queens Leetcode N Queens II

题意 给定一个数字 n n n&#xff0c;形成n*n的棋盘&#xff0c;棋盘上放n个皇后&#xff0c;确保皇后之间不会相互吃&#xff08;皇后可以直线吃&#xff0c;斜线吃&#xff09; 链接 https://leetcode.com/problems/n-queens/description/ 思考 这道题只能暴力枚举所有的…...

0.查找命令

目录 &#x1f349; find - 查找文件 &#x1f347; grep &#x1f353; which &#x1f348;locate 总结: &#x1f349; find - 查找文件 # 语法 # find [搜索范围] [选项] # 选项 # -name<查询方式> 按照指定的文件名查找模式查找文件 # …...

HarmonyOS-初级(一)

文章目录 初级核心技术理念函数的声明和使用类的声明和使用接口声明和使用声明式UI的特征 &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;HarmonyOS专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年11月28日12点50分 初级 HAP可以分为静…...

Oracle 11gR2 坏块修复实例一则

背景 前段时间在 Oracle 11gR2 数据库中发现了坏块问题。环境是 64 位 Linux 平台。本文将详细介绍如何使用 DBMS_REPAIR 进行在线修复&#xff0c;当然也可以基于备份和 RMAN 的修复方法这里暂时不做介绍。 发现坏块 1. 从 alert.log 中发现错误 在 alert.log 文件中发现了…...

解决FinalShell 连接virtual box安装的Linux centos/7系统 一直让输入密码,输入什么密码都没用

问题描述&#xff1a; virtual box安装的Linux centos/7系统默认只允许ssh登录方式&#xff0c;需要配置允许账号密码登录 先登录root账号&#xff08;一定要是root&#xff09;&#xff1a;初始密码为vagrant su 修改ssh配置文件&#xff1a; vi /etc/ssh/sshd_config 修改…...

华为E9000刀箱(HWE9000V2)服务器硬件监控指标解读

随着数据中心规模的不断扩大&#xff0c;服务器的稳定性和可靠性变得尤为重要。华为E9000刀箱&#xff08;HWE9000V2&#xff09;作为一款高性能的服务器设备&#xff0c;其硬件状态的实时监控对于保障业务的连续性和系统的稳定运行至关重要。 监控易作为一款专业的IT基础设施监…...

Python基础学习-12匿名函数lambda和map、filter

目录 1、匿名函数&#xff1a; lambda 2、Lambda的参数类型 3、map、 filter 4、本节总结 1、匿名函数&#xff1a; lambda 1&#xff09;语法&#xff1a; lambda arg1, arg2, …, argN : expression using arg 2&#xff09; lambda是一个表达式&#xff0c;而不是一个语…...

民安:助力提升城市安全水平

随着城市化进程的加速&#xff0c;平安城市的创建成为了社会治理的重要议题。为了解公众对平安城市创建的看法和评价&#xff0c;为提升城市安全水平提供参考&#xff0c;近期某市委托民安智库专业市场调查公司开展了一次安全感满意度调查。 本次调查围绕公共安全、个人安全、…...

Apache Zeppelin:一个基于Web的大数据可视化分析平台

今天给大家推荐一下 Apache Zeppelin&#xff0c;它是一个基于 Web 的交互式数据接入、数据分析、数据可视化以及协作文档 Notebook&#xff0c;类似于 Jupyter Notebook。 Apache Zeppelin 支持使用 SQL、Java、Scala、Python、R 等编程语言进行数据处理和分析&#xff0c;同时…...

「Qt Widget中文示例指南」如何为窗口实现流程布局?(二)

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写&#xff0c;所有平台无差别运行&#xff0c;更提供了几乎所有开发过程中需要用到的工具。如今&#xff0c;Qt已被运用于超过70个行业、数千家企业&#xff0c;支持数百万设备及应用。 本文将展示如何为不…...

【C语言篇】探索 C 语言结构体:从基础语法到数据组织的初体验

我的个人主页 我的专栏&#xff1a;C语言&#xff0c;希望能帮助到大家&#xff01;&#xff01;&#xff01;点赞❤ 收藏❤ 目录 什么是结构体结构体的定义与使用结构体内存布局嵌套结构体与指针结构体数组的操作结构体与函数结构体内存对齐机制位域与结构体的结合动态内存分…...

linux下USB设备状态查询

linux下USB设备状态查询 linux下USB设备状态查询 在buildroot RK3568平台上调试USB视频采集时发现&#xff0c;USB设备经常性断开&#xff0c;为发现其断开的规律&#xff0c;编写脚本记录其断开的时间 linux下USB设备状态查询 #周期性查询 USB设备 cat > /usr/bin/usbenq…...

鼠标前进后退键改双击,键盘映射(AutoHotkey)

初衷&#xff1a; 1.大部分鼠标为不可自定义按键&#xff0c;可以自定义的又很贵。 鼠标左键是双击是很频类很高的操作&#xff0c;鼠标前进/后退按键个人感觉使用频率很低&#xff0c;因此把鼠标前进/后退改为双击还是很合适的。 2.有些短款的键盘没有Home或End键&#xff0c;…...

ubuntu服务器睡眠命令

在 Ubuntu 服务器中&#xff0c;通常不会启用系统睡眠&#xff08;即 suspend&#xff09;模式&#xff0c;因为服务器通常需要保持持续运行以提供服务。但如果你希望让 Ubuntu 服务器进入睡眠状态&#xff0c;你可以使用以下命令&#xff1a; 1. 让系统进入休眠&#xff08;S…...

尚硅谷学习笔记——Java设计模式(一)设计模式七大原则

一、介绍 在软件工程中&#xff0c;设计模式&#xff08;design pattern&#xff09;是对软件设计中普遍存在&#xff08;反复出现&#xff09;的各种问题&#xff0c;提出的解决方案。我们希望我们的软件能够实现复用性、高稳定性、扩展性、维护性、代码重用性&#xff0c;所以…...

Flink——进行数据转换时,报:Recovery is suppressed by NoRestartBackoffTimeStrategy

热词统计案例&#xff1a; 用flink中的窗口函数&#xff08;apply&#xff09;读取kafka中数据&#xff0c;并对热词进行统计。 apply:全量聚合函数&#xff0c;指在窗口触发的时候才会对窗口内的所有数据进行一次计算&#xff08;等窗口的数据到齐&#xff0c;才开始进行聚合…...

技能之发布自己的依赖到npm上

目录 开始 解决 步骤一&#xff1a; 步骤二&#xff1a; 步骤三&#xff1a; 运用 一直以为自己的项目在github上有了&#xff08;之传了github&#xff09;就可以进行npm install下载&#xff0c;有没有和我一样萌萌的同学。没事&#xff0c;萌萌乎乎的不犯罪。 偶然的机…...

COMSOL工作站:配置指南与性能优化

COMSOL Multiphysics 求解的问题类型相当广泛&#xff0c;提供了仿真单一物理场以及灵活耦合多个物理场的功能&#xff0c;供工程师和科研人员来精确分析各个工程领域的设备、工艺和流程。 软件内置的#模型开发器#包含完整的建模工作流程&#xff0c;可实现从几何建模、材料参数…...

Qt导出Excel图表

目的 就是利用Qt导出Excel图表,如果直接画Excel 图表&#xff0c;比较麻烦些&#xff0c;代码写得也复杂了&#xff1b;而直接利用Excel模块就简单了&#xff0c;图表在模块当中已经是现成的了&#xff0c;Qt程序只更改数据就可以了&#xff0c;这篇文章就是记录一下利用模块上…...

分布式协同 - 分布式系统的特性与互斥问题

文章目录 导图概述分布式系统的特性与挑战分布式互斥算法的目标分布式互斥算法集中互斥算法集中互斥算法示意图集中互斥算法流程 基于许可的互斥算法Lamport 算法示意图Lamport 流程 令牌环互斥算法令牌环互斥算法示意图 1. 集中互斥算法&#xff08;Centralized Mutual Exclus…...

windows安装itop

本文介绍 win10 安装 itop 安装WAMP集成环境前 先安装visual c 安装itop前需要安装WAMP集成环境(windowsApacheMysqlPHP) 所需文件百度云盘 通过网盘分享的文件&#xff1a;itop.zip 链接: https://pan.baidu.com/s/1D5HrKdbyEaYBZ8_IebDQxQ 提取码: m9fh 步骤一&#xff1…...

LAMP环境的部署

一、软件安装介绍 在Linux系统中安装软件有rpm安装、yum安装、源码安装等方法&#xff0c;在这里主要给大家介绍 yum 安装&#xff0c;这是一种最简单方便的一种安装方法。 YUM&#xff08;Yellow dog Upadate Modifie&#xff09;是改进版的 RPM 管理器&#xff0c;很好地解…...

Go语言压缩文件处理

目录 Go 语言压缩文件处理1. 压缩文件&#xff1a;Zip函数2. 解压文件&#xff1a;UnZip 函数3. 小结 Go 语言压缩文件处理 在现代的应用开发中&#xff0c;处理压缩文件&#xff08;如 .zip 格式&#xff09;是常见的需求。Go 语言提供了内置的 archive/zip 包来处理 .zip 文…...

rocylinux9.4安装prometheus监控

一.上传软件包 具体的软件包如下&#xff0c;其中kubernetes-mixin是下载的监控kubernetes的一些监控规则、dashbaordd等。 二.Prometheus配置 1.promethes软件安装 #解压上传后的软件包 [rootlocalhost ] cd /opt [rootlocalhost opt]# tar xf prometheus-2.35.3.linux-amd…...

屏幕分辨率|尺寸|颜色深度指纹

一、前端通过window.screen接口获取屏幕分辨率 尺寸 颜色深度&#xff0c;横屏竖屏信息。 二、window.screen c接口实现&#xff1a; 1、third_party\blink\renderer\core\frame\screen.idl // https://drafts.csswg.org/cssom-view/#the-screen-interface[ExposedWindow ] …...

docker-elasticsearch-kibana-logstash

一、安装 Elasticsearch 尝试直接拉取 Elasticsearch 镜像&#xff1a; 执行 docker pull docker.elastic.co/elasticsearch/elasticsearch&#xff0c;拉取失败&#xff0c;错误提示为 “Error response from daemon: manifest for docker.elastic.co/elasticsearch/elasticse…...

个人养老金制度9月底前亮相/抚顺优化seo

一百多年前&#xff0c;有道数学题难住了全世界的数学家&#xff1a;“2的67次方减去1&#xff0c;究竟是质数&#xff0c;还是合数&#xff1f;” 这是一个数论的题目&#xff0c;虽然它的知名度远不如“哥德巴赫猜想”&#xff0c;但是&#xff0c;破解它的难度&#xff0c;…...

美国做电商网站有哪些/关键词优化哪家强

【Entity层】实体层&#xff1a;关系型数据库在代码中的体现 Entity中的类 与 关系型数据库中的二维表 有一一对应关系必须提供get、set、tostring方法&#xff0c;有无餐的构造函数 【DAO层】持久层&#xff1a;控制与数据库的交互 DAO&#xff1a;data access objectDAO层…...

北京网站建设怎么样天/2022近期时事热点素材摘抄

JavaScript基础——小测验1单选题 有两个变量名&#xff0c;myFirstWeb&#xff0c;以及myfirstweb&#xff0c;这两个变量是否引用相同的地址?&#xff08;B&#xff09; A. 相同 B. 不同 多选题 下面哪些JavaScrpit语句是错误的?&#xff08;BDF&#xff09; A. var br…...

企业建设网站需要什么资料/上海培训机构

小G北京 2012/5/15 19:23 eval函数是python最常用于做序列化、反序列化的函数&#xff0c;有些人就会把外部输入的数据&#xff0c;eval一下变成对象&#xff0c;但你不做任何过滤就执行eval的时候可知道&#xff0c;你变成一个很初级的码农了。 命令执行的场景如下&#xff1a…...

丹东网站优化/东莞市网站建设

在生产环境中&#xff0c;我们要安装某些软件往往是不能够直接访问外网进行下载的&#xff0c;所以我们需要通过别的方式将我们需要的软件以及依赖包在有网环境下全量下载下来之后再上传至服务器&#xff0c;下面提供一种centos7中全量下载某个软件及其全量依赖的方法&#xff…...

网站开发 为什么要用缩略图/东莞网络推广平台

①while循环的表达式是循环进行的条件&#xff0c;用作循环条件的表达式中一般至少包括一个能够改变表达式的变量&#xff0c;这个变量称为循环变量②当表达式的值为真(非零)(非空)时&#xff0c;执行循环体&#xff1b;为假(0)时&#xff0c;则循环结束不为0&#xff0c;不为f…...