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

Zookeeper选举算法与提案处理概览

共识算法(Consensus Algorithm)

共识算法即在分布式系统中节点达成共识的算法,提高系统在分布式环境下的容错性。
依据系统对故障组件的容错能力可分为:

  • 崩溃容错协议(Crash Fault Tolerant, CFT) : 无恶意行为,如进程崩溃,只要失败的quorum不过半即可正常提供服务
  • 拜占庭容错协议(Byzantine Fault Tolerant, BFT): 有恶意行为,只要恶意的quorum不过1/3即可正常提供服务

分布式环境下节点之间是没有一个全局时钟和同频时钟,故在分布式系统中的通信天然是异步的。
而在异步环境下是没有共识算法能够完全保证一致性(极端场景下会出现不一致,通常是不会出现)

In a fully asynchronous message-passing distributed system, in which at least one process may have a crash failure,
it has been proven in the famous 1985 FLP impossibility result by Fischer, Lynch and Paterson that a deterministic algorithm for achieving consensus is impossible.

另外网络是否可以未经许可直接加入新节点也是共识算法考虑的一方面,
未经许可即可加入的网络环境会存在女巫攻击(Sybil attack)

分布式系统中,根据共识形成的形式可分为

  • Voting-based Consensus Algorithms: Practical Byzantine Fault Tolerance、HotStuff、Paxos、 Raft、 ZAB …
  • Proof-based Consensus Algorithms: Proof-of-Work、Proof-of-Stake …

Zookeeper模型与架构

A Distributed Coordination Service for Distributed Applications:
ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services.

Zookeeper(后简称zk)定位于分布式环境下的元数据管理,而不是数据库,zk中数据存在内存中,所以不适合存储大量数据。
zk以形如linux文件系统的树形层级结构管理数据,如下图所示:

在这里插入图片描述

每一个节点称为一个znode除了存放用户数据(一般为1KB以内)还包含变更版本、变更时间、ACL信息等统计数据(Stat Structure):

  • czxid: The zxid of the change that caused this znode to be created.
  • mzxid: The zxid of the change that last modified this znode.
  • pzxid: The zxid of the change that last modified children of this znode.
  • ctime: The time in milliseconds from epoch when this znode was created.
  • mtime: The time in milliseconds from epoch when this znode was last modified.
  • version: The number of changes to the data of this znode.
  • cversion: The number of changes to the children of this znode.
  • aversion: The number of changes to the ACL of this znode.
  • ephemeralOwner: The session id of the owner of this znode if the znode is an ephemeral node. If it is not an ephemeral node, it will be zero.
  • dataLength: The length of the data field of this znode.
  • numChildren: The number of children of this znode.

同时znode节点可设置为以下特性:

  • ephemeral: 和session生命周期相同
  • sequential: 顺序节点,比如创建顺序节点/a/b,则会生成/a/b0000000001 ,再次创建/a/b,则会生成/a/b0000000002
  • container: 容器节点,用于存放其他节点的节点,子节点无则它也无了,监听container节点需要考虑节点不存在的情况

Zookeeper集群中节点分为三个角色:

  • Leader:它负责 发起并维护与各 Follower 及 Observer 间的心跳。所有的写操作必须要通过 Leader 完成再由 Leader 将写操作广播给其它服务器。一个 Zookeeper 集群同一时间只会有一个实际工作的 Leader。
  • Follower:它会响应 Leader 的心跳。Follower 可直接处理并返回客户端的读请求,同时会将写请求转发给 Leader 处理,并且负责在 Leader 处理写请求时对请求进行投票。一个 Zookeeper 集群可能同时存在多个 Follower。
  • Observer:角色与 Follower 类似,但是无投票权。

为了保证事务的顺序一致性,ZooKeeper 采用了递增的zxid来标识事务,zxid(64bit)由epoch(32bit)+counter(32bit)组成,如果counter溢出会强制重新选主,开启新纪元,如果epoch满了呢?

读操作可以在任意一台zk集群节点中进行,包括watch操作也是,但写操作需要集中转发给Leader节点进行串行化执行保证一致性。
Leader 服务会为每一个 Follower 服务器分配一个单独的队列,然后将事务 Proposal 依次放入队列中,并根据 FIFO(先进先出) 的策略进行消息发送。Follower 服务在接收到 Proposal 后,会将其以事务日志的形式写入本地磁盘中,并在写入成功后反馈给 Leader 一个 Ack 响应。
当 Leader 接收到超过半数 Follower 的 Ack 响应后,就会广播一个 Commit 消息给所有的 Follower 以通知其进行事务提交,之后 Leader 自身也会完成对事务的提交。而每一个 Follower 则在接收到 Commit 消息后,完成事务的提交。
这个流程和二阶段提交很像,只是ZAB没有二阶段的回滚操作。

ZAB(Zookeeper Atomic Broadcast)

Fast Leader Election(FLE)

  • myid: 即sid,有cfg配置文件配置,每个节点之间不重复
  • logicalclock: 即electionEpoch,选举逻辑时钟

public class FastLeaderElection implements Election {// ...public Vote lookForLeader() throws InterruptedException {self.start_fle = Time.currentElapsedTime();try {/** The votes from the current leader election are stored in recvset. In other words, a vote v is in recvset* if v.electionEpoch == logicalclock. The current participant uses recvset to deduce on whether a majority* of participants has voted for it.*/// 投票箱, sid : VoteMap<Long, Vote> recvset = new HashMap<>();/** The votes from previous leader elections, as well as the votes from the current leader election are* stored in outofelection. Note that notifications in a LOOKING state are not stored in outofelection.* Only FOLLOWING or LEADING notifications are stored in outofelection. The current participant could use* outofelection to learn which participant is the leader if it arrives late (i.e., higher logicalclock than* the electionEpoch of the received notifications) in a leader election.*/// 存放上一轮投票和这一轮投票 & (FOLLOWING/LEADING)状态的peer的投票// 如果有(FOLLOWING/LEADING)的投票来迟了(即已经选出了leader但是当前节点接收ack的notification迟了),// 可根据outofelection来判断leader是否被quorum ack了,是则跟随该leaderMap<Long, Vote> outofelection = new HashMap<>();int notTimeout = minNotificationInterval;synchronized (this) {// 更新当前electionEpochlogicalclock.incrementAndGet();// 更新投票为自己updateProposal(getInitId(), getInitLastLoggedZxid(), getPeerEpoch());}// 投当前的leader一票,即投自己一票sendNotifications();SyncedLearnerTracker voteSet = null;/** Loop in which we exchange notifications until we find a leader*/// 循环直到有leader出现while ((self.getPeerState() == ServerState.LOOKING) && (!stop)) {/** Remove next notification from queue, times out after 2 times* the termination time*/// 拉取其他peer的投票Notification n = recvqueue.poll(notTimeout, TimeUnit.MILLISECONDS);/** Sends more notifications if haven't received enough.* Otherwise processes new notification.*/if (n == null) { // 没收到peer的投票信息if (manager.haveDelivered()) { // 上面的notification都发完了sendNotifications(); // 再发一次} else {manager.connectAll(); // 建立连接}/** 指数退避*/notTimeout = Math.min(notTimeout << 1, maxNotificationInterval);/** When a leader failure happens on a master, the backup will be supposed to receive the honour from* Oracle and become a leader, but the honour is likely to be delay. We do a re-check once timeout happens** The leader election algorithm does not provide the ability of electing a leader from a single instance* which is in a configuration of 2 instances.* */if (self.getQuorumVerifier() instanceof QuorumOracleMaj&& self.getQuorumVerifier().revalidateVoteset(voteSet, notTimeout != minNotificationInterval)) {setPeerState(proposedLeader, voteSet);Vote endVote = new Vote(proposedLeader, proposedZxid, logicalclock.get(), proposedEpoch);leaveInstance(endVote);return endVote;}} else if (validVoter(n.sid) && validVoter(n.leader)) { // 收到其他peer的投票/** Only proceed if the vote comes from a replica in the current or next* voting view for a replica in the current or next voting view.*/// 判断发送投票的peer当前状态switch (n.state) {case LOOKING: // 选主中if (getInitLastLoggedZxid() == -1) {break;}if (n.zxid == -1) {break;}if (n.electionEpoch > logicalclock.get()) { // peer的electionEpoch大于当前节点的electionEpochlogicalclock.set(n.electionEpoch); // 直接快进到大的epoch,即peer的electionEpochrecvset.clear(); // 并清空投票箱// 投票pk// peer投票和当前节点进行投票pk: peerEpoch -> zxid -> myid(sid)if (totalOrderPredicate(n.leader, n.zxid, n.peerEpoch, getInitId(), getInitLastLoggedZxid(), getPeerEpoch())) {//  peer赢了,把当前节点的leader zxid peerEpoch设置为peer的updateProposal(n.leader, n.zxid, n.peerEpoch);} else {// 当前节点赢了,恢复自己的配置updateProposal(getInitId(), getInitLastLoggedZxid(), getPeerEpoch());}// 将上面更新后的自己的投票信息广播出去sendNotifications();} else if (n.electionEpoch < logicalclock.get()) {// 如果peer的electionEpoch比当前节点的electionEpoch小,则直接忽略break;} else// electionEpoch相等,进行投票pk: peerEpoch -> zxid -> myid(sid)if (totalOrderPredicate(n.leader, n.zxid, n.peerEpoch, proposedLeader, proposedZxid, proposedEpoch)) {// pk是peer赢了,跟随peer投票,并广播出去updateProposal(n.leader, n.zxid, n.peerEpoch);sendNotifications();}// 将peer的投票放入投票箱recvset.put(n.sid, new Vote(n.leader, n.zxid, n.electionEpoch, n.peerEpoch));voteSet = getVoteTracker(recvset, new Vote(proposedLeader, proposedZxid, logicalclock.get(), proposedEpoch));if (voteSet.hasAllQuorums()) {// Verify if there is any change in the proposed leaderwhile ((n = recvqueue.poll(finalizeWait, TimeUnit.MILLISECONDS)) != null) {if (totalOrderPredicate(n.leader, n.zxid, n.peerEpoch, proposedLeader, proposedZxid, proposedEpoch)) {recvqueue.put(n);break;}}/** This predicate is true once we don't read any new* relevant message from the reception queue*/if (n == null) {setPeerState(proposedLeader, voteSet);Vote endVote = new Vote(proposedLeader, proposedZxid, logicalclock.get(), proposedEpoch);leaveInstance(endVote);return endVote;}}break;case OBSERVING: // peer是观察者,不参与投票直接返回LOG.debug("Notification from observer: {}", n.sid);break;/** In ZOOKEEPER-3922, we separate the behaviors of FOLLOWING and LEADING.* To avoid the duplication of codes, we create a method called followingBehavior which was used to* shared by FOLLOWING and LEADING. This method returns a Vote. When the returned Vote is null, it follows* the original idea to break switch statement; otherwise, a valid returned Vote indicates, a leader* is generated.** The reason why we need to separate these behaviors is to make the algorithm runnable for 2-node* setting. An extra condition for generating leader is needed. Due to the majority rule, only when* there is a majority in the voteset, a leader will be generated. However, in a configuration of 2 nodes,* the number to achieve the majority remains 2, which means a recovered node cannot generate a leader which is* the existed leader. Therefore, we need the Oracle to kick in this situation. In a two-node configuration, the Oracle* only grants the permission to maintain the progress to one node. The oracle either grants the permission to the* remained node and makes it a new leader when there is a faulty machine, which is the case to maintain the progress.* Otherwise, the oracle does not grant the permission to the remained node, which further causes a service down.** In the former case, when a failed server recovers and participate in the leader election, it would not locate a* new leader because there does not exist a majority in the voteset. It fails on the containAllQuorum() infinitely due to* two facts. First one is the fact that it does do not have a majority in the voteset. The other fact is the fact that* the oracle would not give the permission since the oracle already gave the permission to the existed leader, the healthy machine.* Logically, when the oracle replies with negative, it implies the existed leader which is LEADING notification comes from is a valid leader.* To threat this negative replies as a permission to generate the leader is the purpose to separate these two behaviors.*** */case FOLLOWING: // peer正在following leaderVote resultFN = receivedFollowingNotification(recvset, outofelection, voteSet, n);if (resultFN == null) {break;} else {// 成功选主,返回return resultFN;}case LEADING: // peer 是 leader/** In leadingBehavior(), it performs followingBehvior() first. When followingBehavior() returns* a null pointer, ask Oracle whether to follow this leader.* */Vote resultLN = receivedLeadingNotification(recvset, outofelection, voteSet, n);if (resultLN == null) {break;} else {return resultLN;}default:break;}} else {// 推举的leader或投票的peer不合法,直接忽略// ...}}return null;} finally {// ...}}private Vote receivedFollowingNotification(Map<Long, Vote> recvset, Map<Long, Vote> outofelection,SyncedLearnerTracker voteSet, Notification n) {/** Consider all notifications from the same epoch* together.*/if (n.electionEpoch == logicalclock.get()) { // 同一轮投票//            若对方选票中的electionEpoch等于当前的logicalclock,//            说明选举结果已经出来了,将它们放入recvset。recvset.put(n.sid, new Vote(n.leader, n.zxid, n.electionEpoch, n.peerEpoch, n.state));voteSet = getVoteTracker(recvset, new Vote(n.version, n.leader, n.zxid, n.electionEpoch, n.peerEpoch, n.state));// 判断quorum是否满足选主条件if (voteSet.hasAllQuorums() &&// 判断推举的leader已经被quorum ack了,避免leader挂了导致集群一直在选举中checkLeader(recvset, n.leader, n.electionEpoch)) {// leader是自己,将自己设置为LEADING,否则是FOLLOWING(或OBSERVING)setPeerState(n.leader, voteSet);Vote endVote = new Vote(n.leader, n.zxid, n.electionEpoch, n.peerEpoch);// 清空消费投票的queueleaveInstance(endVote);return endVote;}}// 到这里是// peer的electionEpoch和logicalclock不一致// 因为peer是FOLLOWING,所以在它的electionEpoch里已经选主成功了/** 在跟随peer选出的leader前,校验这个leader合法不合法* Before joining an established ensemble, verify that* a majority are following the same leader.** Note that the outofelection map also stores votes from the current leader election.* See ZOOKEEPER-1732 for more information.*/outofelection.put(n.sid, new Vote(n.version, n.leader, n.zxid, n.electionEpoch, n.peerEpoch, n.state));voteSet = getVoteTracker(outofelection, new Vote(n.version, n.leader, n.zxid, n.electionEpoch, n.peerEpoch, n.state));if (voteSet.hasAllQuorums() && checkLeader(outofelection, n.leader, n.electionEpoch)) {synchronized (this) {logicalclock.set(n.electionEpoch);setPeerState(n.leader, voteSet);}Vote endVote = new Vote(n.leader, n.zxid, n.electionEpoch, n.peerEpoch);leaveInstance(endVote);return endVote;}return null;}private Vote receivedLeadingNotification(Map<Long, Vote> recvset, Map<Long, Vote> outofelection, SyncedLearnerTracker voteSet, Notification n) {/** 在两个节点的集群中(leader+follower),如果follower挂了,recovery之后,因为投票无法过半(follower会首先投自己一票),会找不到leader* In a two-node configuration, a recovery nodes cannot locate a leader because of the lack of the majority in the voteset.* Therefore, it is the time for Oracle to take place as a tight breaker.* */Vote result = receivedFollowingNotification(recvset, outofelection, voteSet, n);if (result == null) {/** Ask Oracle to see if it is okay to follow this leader.* We don't need the CheckLeader() because itself cannot be a leader candidate* */// needOracle,当集群无follower & 集群voter==2 时,if (self.getQuorumVerifier().getNeedOracle() // 且cfg配置中key=oraclePath的文件(默认没有,askOracle默认false)中的值 != '1' 时会走到if里// 这里可参考官网 https://zookeeper.apache.org/doc/current/zookeeperOracleQuorums.html&& !self.getQuorumVerifier().askOracle()) {LOG.info("Oracle indicates to follow");setPeerState(n.leader, voteSet);Vote endVote = new Vote(n.leader, n.zxid, n.electionEpoch, n.peerEpoch);leaveInstance(endVote);return endVote;} else {LOG.info("Oracle indicates not to follow");return null;}} else {return result;}}// ...
}

提案处理

在这里插入图片描述

所有的提案均通过leader来提,follower接受的提案会转发到leader。
zk采用责任链模式对请求进行处理,不同的角色(leader/follower/observer)对应不同的责任链:

在这里插入图片描述

以下是leader的各个Processor的作用

  • LeaderRequestProcessor: Responsible for performing local session upgrade. Only request submitted directly to the leader should go through this processor.
  • PrepRequestProcessor: It sets up any transactions associated with requests that change the state of the system
  • ProposalRequestProcessor: 调用Leader#propose将proposal加入发送给follower的queue,由LeaderHandler异步发送给follower和处理follower的ack
  • SyncRequestProcessor: 将request写磁盘
  • AckRequestProcessor: ack leader自己的request
  • CommitProcessor: 提交提案。CommitProcessor本身是一个线程,上游调用先把request加入队列,然后异步消费处理
  • ToBeAppliedRequestProcessor: simply maintains the toBeApplied list
  • FinalRequestProcessor: This Request processor actually applies any transaction associated with a request and services any queries

接收follower的ack并提交走下面的调用:

org.apache.zookeeper.server.quorum.Leader.LearnerCnxAcceptor#run
org.apache.zookeeper.server.quorum.Leader.LearnerCnxAcceptor.LearnerCnxAcceptorHandler#run
org.apache.zookeeper.server.quorum.Leader.LearnerCnxAcceptor.LearnerCnxAcceptorHandler#acceptConnections
org.apache.zookeeper.server.quorum.LearnerHandler#run
org.apache.jute.BinaryInputArchive#readRecord
org.apache.zookeeper.server.quorum.LearnerMaster#processAck 这里如果满足quorum则调用CommitProcessor
org.apache.zookeeper.server.quorum.Leader#tryToCommit
org.apache.zookeeper.server.quorum.Leader#commit (leader 发送commit消息给follower,此时leader还不一定提交了,因为异步处理的) 
org.apache.zookeeper.server.quorum.Leader#inform (leader 发送inform消息给observer,此时leader还不一定提交了,因为异步处理的)

判断是否满足quorum的方法为:SyncedLearnerTracker#hasAllQuorums

public class SyncedLearnerTracker { // Proposal的父类,即每个提案一个Trackerpublic static class QuorumVerifierAcksetPair {private final QuorumVerifier qv; // 每一个zxid就是一个QuorumVerifierprivate final HashSet<Long> ackset; // ack的sid set...}protected ArrayList<QuorumVerifierAcksetPair> qvAcksetPairs = new ArrayList<>();...public boolean hasAllQuorums() {for (QuorumVerifierAcksetPair qvAckset : qvAcksetPairs) {if (!qvAckset.getQuorumVerifier().containsQuorum(qvAckset.getAckset())) {return false;}}return true;}...
}

最终调用QuorumMaj#containsQuorum

public class QuorumMaj implements QuorumVerifier {...protected int half = votingMembers.size() / 2;/*** Verifies if a set is a majority. Assumes that ackSet contains acks only* from votingMembers*/public boolean containsQuorum(Set<Long> ackSet) {return (ackSet.size() > half);}...

参考

  • Consensus Algorithms in Distributed Systems
  • FLP Impossibility Result
  • zookeeperInternals
  • 详解分布式协调服务 ZooKeeper,再也不怕面试问这个了
  • Lecture 8: Zookeeper
  • ZooKeeper: Wait-free coordination for Internet-scale systems
  • diff_acceptepoch_currentepoch
  • Zookeeper(FastLeaderElection选主流程详解)
  • zookeeper-framwork-design-message-processor-leader

相关文章:

Zookeeper选举算法与提案处理概览

共识算法(Consensus Algorithm) 共识算法即在分布式系统中节点达成共识的算法&#xff0c;提高系统在分布式环境下的容错性。 依据系统对故障组件的容错能力可分为&#xff1a; 崩溃容错协议(Crash Fault Tolerant, CFT) : 无恶意行为&#xff0c;如进程崩溃&#xff0c;只要…...

深入了解 Adam 优化器对显存的需求:以 LLaMA-2 7B 模型为例 (中英双语)

中文版 深入了解 Adam 优化器对显存的额外需求&#xff1a;模型参数与优化器状态的显存开销分析 在深度学习模型的训练过程中&#xff0c;显存是一个关键的资源&#xff0c;尤其在处理大型语言模型或深度神经网络时。训练时的显存需求不仅包括模型参数本身&#xff0c;还涉及…...

数据分析学习

数据分析的定义 数据分析是通过对收集到的数据进行清理、转换、建模、分析和解释&#xff0c;从中提取有用的信息和洞察&#xff0c;以帮助做出更好的决策。数据分析可以应用于各种领域&#xff0c;比如商业、金融、医疗、市场营销等&#xff0c;目的是通过数据来发现模式、趋…...

PaddleOCR:一款高性能的OCR工具介绍

一、引言 随着人工智能技术的不断发展&#xff0c;光学字符识别&#xff08;OCR&#xff09;技术在各行各业得到了广泛应用。OCR技术能够将图片、扫描件等非结构化数据中的文字信息提取出来&#xff0c;转换为可编辑的文本格式。在我国&#xff0c;百度开源了一款优秀的OCR工具…...

Transformers快速入门代码解析(一):注意力机制——Attention:Scaled Dot-product Attention

Attention&#xff1a;Scaled Dot-product Attention 引言Scaled Dot-product Attention代码 引言 请注意&#xff01;&#xff01;&#xff01;本博客使用了教程Transformers快速入门中的全部代码&#xff01;&#xff01;&#xff01; 只在我个人理解的基础上为代码添加了注释…...

Git中HEAD、工作树和索引的区别

在Git版本控制系统中&#xff0c;HEAD、工作树&#xff08;Working Tree&#xff09;和索引&#xff08;Index&#xff09;是三个非常重要的概念&#xff0c;它们分别代表了不同的状态或区域&#xff0c;下面我将对这三个概念进行详细的解释。 HEAD 定义&#xff1a;HEAD是一…...

【python量化教程】如何使用必盈API的股票接口,获取最新实时交易数据

实时交易数据简介 股票实时交易数据涵盖股票价格、成交量、涨跌幅等多类信息。其在股票交易中极为关键&#xff0c;高速准确的数据对各方意义重大。投资者可借此及时捕捉机会、优化策略与降低风险&#xff1b;实时准确的实时交易数据是股票市场有效运转的核心要素之一。 使用…...

【C++】动态内存与智能指针——shared_ptr 和 new 结合使用

12.1.3 shared_ptr 和 new 结合使用 如上文所述&#xff0c;如果我们不初始化一个智能指针&#xff0c;那么它将会被初始化为一个空指针&#xff08;需要注意的是&#xff0c;智能指针与普通指针在此处有着非常明显的区别。如果只声明某个类型的普通指针&#xff0c;而不对它进…...

遥感数据集:FTW全球农田边界和对应影像数据,约160万田块边界及7万多个样本

Fields of The World (FTW) 是一个面向农业田地边界实例分割的基准数据集&#xff0c;旨在推动机器学习模型的发展&#xff0c;满足全球农业监测对高精度、可扩展的田地边界数据的需求。该数据集由kerner-lab提供&#xff0c;于2024年8月28日发布&#xff0c;主要特征包括&…...

马斯克的 AI 游戏工作室:人工智能与游戏产业的融合新纪元

近日&#xff0c;马斯克在 X 平台&#xff08;前身为 Twitter&#xff09;发文称&#xff0c;“太多游戏工作室被大型企业所拥有&#xff0c;xAI 将启动一个 AI 游戏工作室&#xff0c;让游戏再次变得精彩”。这一言论不仅展示了马斯克对游戏行业现状的不满&#xff0c;也揭示了…...

URDF(描述机器人模型)和SDF(Gazebo中用于描述仿真环境)

使用URDF&#xff08;Unified Robot Description Format&#xff09; URDF是ROS中用于描述机器人模型的XML格式文件。你可以使用XML文件定义机器人的几何形状、惯性参数、关节和链接等。 示例URDF文件&#xff08;my_robot.urdf&#xff09;&#xff1a; <?xml version&…...

力扣380:O(1)时间插入、删除和获取随机数

实现RandomizedSet 类&#xff1a; RandomizedSet() 初始化 RandomizedSet 对象bool insert(int val) 当元素 val 不存在时&#xff0c;向集合中插入该项&#xff0c;并返回 true &#xff1b;否则&#xff0c;返回 false 。bool remove(int val) 当元素 val 存在时&#xff0…...

【C++boost::asio网络编程】有关socket的创建和连接的笔记

socket的创建和连接 tcp客户端创建端点tcp服务端创建端点创建socket创建TCP 服务器端的 acceptor 套接字创建 acceptor 套接字并绑定客户端连接到服务器通过ip地址解析通过域名解析 服务端接收新连接 tcp客户端创建端点 int client_end_point() {std::string raw_ip_address …...

超级灵感:前端页面功能统一管理方案

前端页面功能统一管理方案 引言 我和朋友聊天想到一个灵感&#xff0c;关于支付状态机管理&#xff0c;这个类可以让我们知道具体上一个状态和下一个状态&#xff0c;这是由于那个事件触发改变&#xff0c;这个功能设计非常好&#xff01; 从而讨论出为什么我们不能把某一个…...

力扣第 77 题 组合

题目描述 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按任意顺序返回答案。 示例 示例 1 输入&#xff1a; n 4, k 2输出&#xff1a; [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]示例 2 输入&#xff1a; n 1, k …...

(超详细图文)PLSQL Developer 配置连接远程 Oracle 服务

1、下载配置文件 &#xff08;超详细图文详情&#xff09;Navicat 配置连接 Oracle-CSDN博客 将下载的文件解压到单独文件夹&#xff0c;如&#xff1a;D:\App\App_Java\Oracle\instantclient-basic-windows.x64-19.25.0.0.0dbru 2、配置 打开 PLSQL Developer&#xff0c;登…...

元器件选型与参数13 电源的分类-线性电源参数 RT9013 AMS1117 PCB布局布线

目录 一、线性电源 1、重要参数 2、线性电源效率一定低吗 3、线性电源并联扩流 4、常见电路 RT9013-LDO AMS1117-xx-LDO 5、布局布线 6、外置输入与电池供电 7、单片机控制其他模组供电实现低功耗 二、开关电源与线性电源配合 1、高效率与低噪声 DC-DC电源大致分为…...

RHEL7+Oracle11.2 RAC集群-多路径(multipath+udev)安装步骤

RHEL7Oracle11.2RAC集群-多路径&#xff08;multipathudev&#xff09;安装 配置虚拟存储 使用StarWind Management Console软件&#xff0c;配置存储 dggrid1: 1g*3 Dggrid2: 1g*3 Dgsystem: 5g*1 系统表空间&#xff0c;临时表空间&#xff0c;UNDO&#xff0c;参数文件…...

每日速记10道java面试题03

其他资料 每日速记10道java面试题01-CSDN博客 每日速记10道java面试题02-CSDN博客 目录 一、你使用过java的反射机制吗&#xff1f;如何应用反射&#xff1f; 二、什么是泛型&#xff1f;泛型的作用是什么&#xff1f; 三、java的泛型擦除是什么&#xff1f; 四、Java 中…...

Vue 3 的双向绑定原理

Vue 3 的双向绑定原理是基于 响应式系统 和 数据劫持 技术来实现的。在 Vue 3 中&#xff0c;双向绑定通常是通过 v-model 指令来完成的&#xff0c;它本质上是数据的双向同步&#xff1a;当数据改变时&#xff0c;视图自动更新&#xff0c;反之&#xff0c;视图的修改也会更新…...

如何使用 Chrome 无痕浏览模式访问网站?

无痕浏览&#xff08;Incognito Mode&#xff09;是 Google Chrome 浏览器提供的一种隐私保护功能&#xff0c;它允许用户在一个独立的会话中浏览网页&#xff0c;而不会记录用户的浏览历史、下载历史、表单数据等。这对于希望保护个人隐私或进行临时性匿名浏览的用户来说非常有…...

Idea 2024.3 突然出现点击run 运行没有反应,且没有任何提示。

写这篇文章的目的是为了提供一个新的解决思路&#xff0c;因为存在同病不同原因。 如果你进行了1. 检查运行配置 (Run Configuration) 2. 清理和重建项目 3. 清除缓存并重启 IDEA 4.排除kotlin 5.重装idea等等操作之后仍然没有解决&#xff0c;可以试着按一下步骤进行解决。 检…...

【小白学机器学习36】关于独立概率,联合概率,交叉概率,交叉概率和,总概率等 概念辨析的例子

目录 1 先说结论 2 联合概率 3 边缘概率 4 (行/列)边缘概率的和 总概率1 5 条件概率 5.1 条件概率的除法公式 5.2 条件概率和联合概率区别 1 先说结论 关于独立概率&#xff0c;联合概率&#xff0c;交叉概率&#xff0c;交叉概率和&#xff0c;总概率 类型含义 …...

Spring Boot 项目——分层架构

在创建一个 Spring Boot 项目时&#xff0c;为了提高代码的可维护性、可扩展性和清晰度&#xff0c;通常会按照一定的分层架构进行设计。常见的分层架构包括以下几层&#xff1a; 1. Controller 层&#xff08;Web 层&#xff09; 作用&#xff1a;接收用户请求&#xff0c;并…...

wordpress网站首页底部栏显示网站备案信息

一、页脚文件footer.php 例如&#xff0c;wordpress主题使用的是simple-life主题&#xff0c;服务器IP为192.168.68.89,在wordpress主题文件中有个页脚文件footer.php&#xff0c;这是一个包含网站页脚代码的文件。 footer.php 路径如下&#xff1a; /www/wwwroot/192.168.68…...

python面向对象编程练习

学生成绩管理系统 定义一个Student类&#xff0c;包括属性&#xff08;姓名、成绩&#xff09;和方法&#xff08;设置成绩、获取成绩、计算平均成绩&#xff09;。 实例化多个学生对象并调用方法。 功能说明&#xff1a; Student 类&#xff1a; init(self, name)&#xff1a;…...

OpenCV_Code_LOG

孔洞填充 void fillHole(const Mat srcBw, Mat &dstBw) {Size m_Size srcBw.size();Mat TempMat::zeros(m_Size.height2,m_Size.width2,srcBw.type());//延展图像srcBw.copyTo(Temp(Range(1, m_Size.height 1), Range(1, m_Size.width 1)));cv::floodFill(Temp, Point(…...

力扣第 74 题是 搜索二维矩阵

题目描述 给定一个 m x n 的矩阵 matrix 和一个目标值 target&#xff0c;请你编写一个函数来判断目标值 target 是否在矩阵中。 每行的元素按升序排列。每列的元素按升序排列。 示例 1 输入&#xff1a; matrix [[1, 4, 7, 11],[2, 5, 8, 12],[3, 6, 9, 16],[10, 13, 14…...

[极客大挑战 2019]BabySQL--详细解析

信息搜集 进入界面&#xff1a; 输入用户名为admin&#xff0c;密码随便输一个&#xff1a; 发现是GET传参&#xff0c;有username和password两个传参点。 我们测试一下password点位能不能注入&#xff1a; 单引号闭合报错&#xff0c;根据报错信息&#xff0c;我们可以判断…...

实现Linux平台自定义协议族

一 简介 我们常常在Linux系统中编写socket接收TCP/UDP协议数据&#xff0c;大家有没有想过它怎么实现的&#xff0c;如果我们要实现socket接收自定义的协议数据又该怎么做呢&#xff1f;带着这个疑问&#xff0c;我们一起往下看吧~~ 二 Linux内核函数简介 在Linux系统中要想…...

网站做qq链接代码/什么是网络整合营销

之前有一篇写过pycharm远程访问服务器&#xff0c;这里还写vscode的一个类似功能理由有两个。vscode相比于pycharm占用的内存要小。vscode远程访问不要钱&#xff01;&#xff01;&#xff01;而pycharm必须要付费的专业版才拥有这个功能。但是vscode也有不好的地方&#xff0c…...

做网站建本地环境作用/seo网站推广的主要目的包括

前面说完了此项目的创建及数据模型设计的过程。如果未看过&#xff0c;可以到这里查看&#xff0c;并且项目源码已经放大到github上,可以去这里下载。代码也已经部署到sina sea上&#xff0c;地址为http://fengzheng.sinaapp.com/先跳过视图展示及表单处理的部分&#xff0c;先…...

凡科网站模板/又一病毒来了比新冠可怕

前言 之前我有整理过一系列文章“支付功能如何测试&#xff1f;”&#xff0c;“抖音直播要如何测试”&#xff0c;“微信红包如何测试”&#xff0c;很多学生说是及时雨&#xff0c;帮助了他们的测试面试&#xff0c;需要的同学可以点击查看&#xff08;附上文章链接&#xf…...

做优惠卷网站/冯耀宗seo教程

npm 初始化by Zell Liew由Zell Liew 初始化npm的最佳时间 (The best time to npm init) When should you npm init?您应该何时启动npm init &#xff1f; Most developers run npm init right after creating and navigating into a new project.大多数开发人员在创建并导航…...

高校网站一般采用什么网页布局/互联网怎么赚钱

电脑A ip &#xff1a;192.168.1.186 电脑B ip :192.168.1.1 用电脑A 去链接电脑B的本地数据库 1.互相 ping 看能否访问 如图 &#xff08;判断是否在一个局域网&#xff09; 2.给电脑A授权创建用户 电脑B操作 允许用户myuser从ip为 192.168.1.186 的主机连接到mysql服务器&a…...

自己做h5网站/全国疫情高峰感染高峰

与Non-mutating Algorithms相比&#xff0c;变易算法能修改容器元素数据&#xff0c;可进行序列数据的复制、交换、替换、填充、移除、旋转、随机抖动、分割。还是参考叶至军的那本书以及网站Cplusplus.com copy 元素复制。该函数用于容器间元素拷贝&#xff0c;将迭代器区间[…...