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/b/0000000001 ,再次创建/a/b,则会生成/a/b/0000000002
- 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 systemProposalRequestProcessor
: 调用Leader#propose
将proposal加入发送给follower的queue,由LeaderHandler异步发送给follower和处理follower的ackSyncRequestProcessor
: 将request写磁盘AckRequestProcessor
: ack leader自己的requestCommitProcessor
: 提交提案。CommitProcessor
本身是一个线程,上游调用先把request加入队列,然后异步消费处理ToBeAppliedRequestProcessor
: simply maintains the toBeApplied listFinalRequestProcessor
: 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) 共识算法即在分布式系统中节点达成共识的算法,提高系统在分布式环境下的容错性。 依据系统对故障组件的容错能力可分为: 崩溃容错协议(Crash Fault Tolerant, CFT) : 无恶意行为,如进程崩溃,只要…...
Jmeter中的断言
7)断言 1--响应断言 功能特点 数据验证:验证响应数据是否包含或不包含特定的字符串、模式或值。多种匹配类型:支持多种匹配类型,如文本、正则表达式、文档等。灵活配置:可以设置多个断言条件,满足复杂的测…...
【通俗理解】隐变量的变分分布探索——从公式到应用
【通俗理解】隐变量的变分分布探索——从公式到应用 关键词提炼 #隐变量 #变分分布 #概率模型 #公式推导 #期望最大化 #机器学习 #变分贝叶斯 #隐马尔可夫模型 第一节:隐变量的变分分布的类比与核心概念【尽可能通俗】 隐变量的变分分布就像是一场“捉迷藏”游戏…...
Vivado程序固化到Flash
在上板调试FPGA时,通常使用JTAG接口下载程序到FPGA芯片中,FPGA本身是基于RAM工艺的器件,因此掉电后会丢失芯片内的程序,需要重新烧写程序。但是当程序需要投入使用时不能每一次都使用JTAG接口下载程序,一般FPGA的外围会…...
铲屎官进,2024年宠物空气净化器十大排行,看看哪款吸毛最佳?
不知道最近换毛季,铲屎官们还承受的住吗?我家猫咪每天都在表演“天女散花”,家里没有一块干净的地方,空气中也都是堆积的浮毛,幸好有宠物空气净化器这种清理好物。宠物空气净化器针对宠物浮毛设计,可以有效…...
SpringBoot 项目中使用 spring-boot-starter-amqp 依赖实现 RabbitMQ
文章目录 前言1、application.yml2、RabbitMqConfig3、MqMessage4、MqMessageItem5、DirectMode6、StateConsumer:消费者7、InfoConsumer:消费者 前言 本文是工作之余的随手记,记录在工作期间使用 RabbitMQ 的笔记。 1、application.yml 使…...
嵌入式硬件实战提升篇(二)PCB高速板设计 FPGA核心板带DDR3 PCB设计DDR全面解析
引言:设计一款高速板,供读者学习,FPGA核心板,带一颗DDR3内存,FPGA型号:XC6SLX16-2FTG256C。 随着嵌入式硬件技术的快速发展,高速板设计逐渐成为嵌入式系统设计中的核心技术之一。高速板的设计要…...
2044:【例5.12】回文字串
【题目描述】 输入一串字符,字符个数不超过100,且以“.”结束。 判断它们是否构成回文。 【输入】 一行字符串。 【输出】 是否为回文串。是输出“Yes”,否输出“No。” 【输入样例】 abccb 【输出样例】 No 代码实现 #include <stdio.h> /*2044&#x…...
Sui 链游戏开发实战:用 Move 写一个链上剪刀石头布游戏!
系列文章目录 Task1:hello move🚪 Task2:move coin🚪 Task3:move nft🚪 Task4:move game🚪 更多精彩内容,敬请期待!✌️ 文章目录 系列文章目录前言什么是 …...
Prometheus告警带图完美解决方案
需求背景 告警分析处理流程 通常我们收到 Prometheus 告警事件通知后,往往都需要登录 Alertmanager 页面查看当前激活的告警,如果需要分析告警历史数据信息,还需要登录 Prometheus 页面的在 Alerts 中查询告警 promQL 表达式,然…...
深度学习模型:循环神经网络(RNN)
一、引言 在深度学习的浩瀚海洋里,循环神经网络(RNN)宛如一颗独特的明珠,专门用于剖析序列数据,如文本、语音、时间序列等。无论是预测股票走势,还是理解自然语言,RNN 都发挥着举足轻重的作用。…...
分布式在线评测系统
OnlineJudge 前言所用技术开发环境 1. 需求分析2. 项目宏观结构3. compile_server服务设计3.1 compiler服务设计3.2 runner服务设计3.3 compile_run3.4 compile_server.cpp 4. oj_server服务设计4.1 model设计4.2 view设计4.3 control设计4.3.1 获取题目列表功能4.3.2 获取单个…...
Unity中动态生成贴图并保存成png图片实现
实现原理: 要生成长x宽y的贴图,就是生成x*y个像素填充到贴图中,如下图: 如果要改变局部颜色,就是从x1到x2(x1<x2),y1到y2(y1<y2)这个范围做处理, 或者要想做圆形就是计算距某个点(x1,y1&…...
鸿蒙多线程开发——sendable共享容器
1、异步锁机制 在介绍共享容器之前,先介绍异步锁机制。 为了解决多线程并发任务间的数据竞争问题,ArkTS引入了异步锁能力。异步锁可能会被类对象持有,因此为了更方便地在并发实例间获取同一个异步锁对象,AsyncLock对象支持跨线程…...
五天SpringCloud计划——DAY1之mybatis-plus的使用
一、引言 咱也不知道为啥SpringCloud课程会先教mybatis-plus的使用,但是教都教了,就学了吧,学完之后觉得mybatis-plus中的一些方法还是很好用了,本文作为我学习mybatis-plus的总结提升,希望大家看完之后也可以熟悉myba…...
Vue.js基础——贼简单易懂!!(响应式 ref 和 reactive、v-on、v-show 和 v-if、v-for、v-bind)
Vue.js是一个渐进式JavaScript框架,用于构建用户界面。它专门设计用于Web应用程序,并专注于视图层。Vue允许开发人员创建可重用的组件,并轻松管理状态和数据绑定。它还提供了一个虚拟DOM系统,用于高效地渲染和重新渲染组件。Vue以…...
警钟长鸣,防微杜渐,遨游防爆手机如何护航安全生产?
近年来,携非防爆手机进入危险作业区引发爆炸的新闻屡见报端。2019年山西某化工公司火灾,2018年延安某煤业瓦斯爆炸,均因工人未用防爆手机产生静电打火引发。涉爆行业领域企业量大面广,相当一部分企业作业场所人员密集,…...
中国科学院大学研究生学术英语读写教程 Unit7 Materials Science TextA 原文和翻译
中国科学院大学研究生学术英语读写教程 Unit7 Materials Science TextA 原文和翻译 Why Is the Story of Materials Really the Story of Civilisation? 为什么材料的故事实际上就是文明的故事? Mark Miodownik 1 Everything is made of something. Take away co…...
win10中使用ffmpeg和MediaMTX 推流rtsp视频
在win10上测试下ffmpeg推流rtsp视频,需要同时用到流媒体服务器MediaMTX 。ffmpeg推流到流媒体服务器MediaMTX ,其他客户端从流媒体服务器拉流。 步骤如下: 1 下载MediaMTX github: Release v1.9.3 bluenviron/mediamtx GitHub…...
代码美学2:MATLAB制作渐变色
效果: %代码美学:MATLAB制作渐变色 % 创建一个10x10的矩阵来表示热力图的数据 data reshape(1:100, [10, 10]);% 创建热力图 figure; imagesc(data);% 设置颜色映射为“cool” colormap(cool);% 在热力图上添加边框 axis on; grid on;% 设置热力图的颜色…...
gitlab:使用脚本批量下载项目,实现全项目检索
目的 当需要知道gitlab中所有项目是否存在某段代码时,gitlab免费版只提供了当个项目内的检索,当项目过多时一个个查太过繁琐。下面通过 GitLab API 将指定 Group 下的所有项目克隆到本地。此脚本会自动获取项目列表并逐一克隆它们,再在本地进…...
大型语言模型LLM - Finetuning vs Prompting
资料来自台湾大学李宏毅教授机器学课程ML 2023 Spring,如有侵权请通知下架 台大机器学课程ML 2023 Springhttps://speech.ee.ntu.edu.tw/~hylee/ml/2023-spring.php2023/3/10 课程 機器如何生成文句 内容概要 主要探讨了大型语言模型的两种不同期待及其导致的两类…...
【Python中while循环】
一、深拷贝、浅拷贝 1、需求 1)拷贝原列表产生一个新列表 2)想让两个列表完全独立开(针对改操作,读的操作不改变) 要满足上述的条件,只能使用深拷贝 2、如何拷贝列表 1)直接赋值 # 定义一个…...
Selenium 包介绍
诸神缄默不语-个人CSDN博文目录 Selenium 是一个强大的工具,主要用于自动化 Web 浏览器的操作。它支持多种编程语言(如 Python、Java、C# 等)和主流浏览器(如 Chrome、Firefox、Safari、Edge 等),广泛应用…...
量化交易系统开发-实时行情自动化交易-4.4.做市策略
19年创业做过一年的量化交易但没有成功,作为交易系统的开发人员积累了一些经验,最近想重新研究交易系统,一边整理一边写出来一些思考供大家参考,也希望跟做量化的朋友有更多的交流和合作。 接下来继续说说做市策略原理。 做市策…...
C++设计模式(单例模式)
一、介绍 1.动机 在软件系统中,经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性、以及良好的效率。 如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例? 这应该是类设计者的…...
图的深度优先搜索算法DFS
深度优先搜索(DFS)就是一种寻找图中各个顶点的方法。想象一下,如果你在一个迷宫里探险,你会怎么做呢?你可能会选择一直走到尽头,直到找不到路为止,然后再回过头来试试其他的路,这就是…...
自动泊车“哐哐撞大墙”,小米SU7智驾功能bug缠身?
文/王俣祺 导语:小米SU7,自带热度与科技光环的“流量神车”,近日却以一种极为“狼狈”的方式闯入大众视野。多达70余辆小米SU7陷入“泊车魔咒”,瞬间在网络上炸开了锅。从“科技控”到“惹祸精”的背后,究竟藏着怎样的…...
Linux宝塔部署wordpress网站更换服务器IP后无法访问管理后台和打开网站页面显示错乱
一、背景: wordpress网站搬家,更换服务器IP后,如果没有域名时,使用服务器IP地址无法访问管理后台和打开网站页面显示错乱。 二、解决方法如下: 1.wordpress搬家后,在新服务器上,新建站点时&am…...
Http文件上传
方式一:HttpClient public static String uploadFile(String url, Map<String, FileWrapper> fileParam, Map<String,String> otherParam){long start System.currentTimeMillis();log.info("uploadFile url: {}.",url);HttpClient client …...
哈希C++
文章目录 一.哈希的概念1.直接定址法2.负载因子 二.哈希函数1.除法散列法 / 除留余数法2.乘法散列法3.全域散列法(了解) 三.处理哈希冲突哈希冲突:1.开放定址法(1)线性探测:(2)二次探…...
C++11(中)
C11(中) 1.可变参数模板1.1.使用场景 2.lambda表达式(重要)2.1.使用说明2.2.函数对象与lambda表达式 3.线程库3.1.thread3.2.atomic原子库操作3.3.mutex3.3.1.mutex的种类3.3.2.lock_guard3.3.3.unique_lock 🌟&#x…...
vim 如何高亮/取消高亮
高亮 :在ESC模式下使用 shift # 取消高亮:在ESC模式下输入英文输入 :nohl (no highlight)...
C#中面试的常见问题008
1.内存泄露 内存泄露的原因: 未释放动态分配的内存:在使用malloc、new等动态内存分配函数后,未能正确释放内存。引用计数错误:在引用计数管理内存的语言中,增加引用计数但未相应减少,导致内存无法释放。循…...
【系统架构设计师】真题论文: 论数据访问层设计技术及其应用(包括解题思路和素材)
更多内容请见: 备考系统架构设计师-专栏介绍和目录 文章目录 真题题目(2016年 试题3)解题思路论文素材参考(1)数据访问层设计 JDBC 技术(2)ORM 框架技术 - Hibernate(3)ORM 框架技术 - MyBatis(4)数据访问层设计模式 - DAO 模式(5)数据访问层设计模式 - Repositor…...
力扣整理版九:贪心算法(待整理)
局部最优 全局最优 局部最优可以推出全局最优 并且想不出反例 ----------------------------- (1) 455 分发饼干 (2) 1005 k次取反后最大化的数组和 (3) 860 柠檬水找零 (2) 376 摆动序列 (3) 122 买卖股票的最佳时机2 (4) 135 分发糖果 (4) 55 跳跃游戏 (5) 45 跳…...
香橙派--安装RKMPP、x264、libdrm、FFmpeg(支持rkmpp)以及opencv(支持带rkmpp的ffmpeg)(适用于RK3588平台)
1. 安装RKMPP git clone https://github.com/rockchip-linux/mppcd mpp/build/linux/aarch64./make-Makefiles.bashmake -j8sudo make installRKMPP:用于编解码测试,支持RK3588平台。 2. 安装x264 git clone https://code.videolan.org/videolan/x264…...
计算机毕业设计Python+大模型美食推荐系统 美食可视化 美食数据分析大屏 美食爬虫 美团爬虫 机器学习 大数据毕业设计 Django Vue.js
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
1138:将字符串中的小写字母转换成大写字母
【题目描述】 给定一个字符串,将其中所有的小写字母转换成大写字母。 【输入】 输入一行,包含一个字符串(长度不超过100,可能包含空格)。 【输出】 输出转换后的字符串。 【输入样例】 helloworld123Ha 【输出样例】…...
Wireshark抓取HTTPS流量技巧
一、工具准备 首先安装wireshark工具,官方链接:Wireshark Go Deep 二、环境变量配置 TLS 加密的核心是会话密钥。这些密钥由客户端和服务器协商生成,用于对通信流量进行对称加密。如果能通过 SSL/TLS 日志文件(例如包含密钥的…...
Unity UGUI原理剖析
UI最重要的两部分 UI是如何渲染出来的点击事件如何触发何时发生UI重绘 1:UI如何渲染出来的 UI渲染一定是有顶点的,没有顶点就没法确定贴图的采样,UGUI的顶点在一张Mesh上创建,经过渲染管线UI就渲染到屏幕上了,UI的渲染…...
实现Excel文件和其他文件导出为压缩包,并导入
导出 后端: PostMapping("/exportExcelData")public void exportExcelData(HttpServletRequest request, HttpServletResponse response, RequestBody ResData resData) throws IOException {List<Long> menuIds resData.getMenuIds();List<Co…...
Linux:基础开发工具
目录 软件包管理器yum 什么是软件包? 查看软件包 安装软件 卸载软件 vim vim的基本操作 gcc/g使用 预处理 编译 汇编 连接 make/Makefile .PHONY伪目标 定义使用变量 版本控制器Git 安装git git的使用 git add git commit git push git pull …...
【mac】终端左边太长处理,自定义显示名称(terminal路径显示特别长)
1、打开终端 2、步骤 (1)修改~/.zshrc文件 nano ~/.zshrc(2)添加或修改PS1,我是自定义了名字为“macminiPro” export PS1"macminiPro$ "(3)使用 nano: Ctrl o (字母…...
嵌入式硬件设计:从概念到实现的全流程
嵌入式硬件设计是现代电子技术中一个至关重要的领域,涉及从硬件架构设计到硬件调试的各个方面。它为我们日常生活中的各类智能设备、家电、工业控制系统等提供了强大的支持。本文将介绍嵌入式硬件设计的基本流程、关键技术、常用工具以及常见的挑战和解决方案&#…...
【Nginx】核心概念与安装配置解释
文章目录 1. 概述2. 核心概念2.1.Http服务器2.2.反向代理2.3. 负载均衡 3. 安装与配置3.1.安装3.2.配置文件解释3.2.1.全局配置块3.2.2.HTTP 配置块3.2.3.Server 块3.2.4.Location 块3.2.5.upstream3.2.6. mine.type文件 3.3.多虚拟主机配置 4. 总结 1. 概述 Nginx是我们常用的…...
数据库-MySQL-MybatisPlus实战
文章目录 前言一、整合mybatis-plus二、CRUD操作1、insert操作2、update操作3、delete操作 三、条件构造器(Wrapper)QueryWrapperUpdateWrapperLambdaQueryWrapperLambdaUpdateWrapper 四、分页查询五、自定义主键生成器六、总结 前言 mybatis相信都不陌生,目前互联…...
Vue2学习记录
前言 这篇笔记,是根据B站尚硅谷的Vue2网课学习整理的,用来学习的 如果有错误,还请大佬指正 Vue核心 Vue简介 Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。 它基于标准 HTML、CSS 和 JavaScr…...
thinkphp中对请求封装
请求的封装 //调用 $res Http::post($this->baseUrl . $url,$params,[CURLOPT_HTTPHEADER > [Content-Type: application/json,Content-Length: . strlen($params),],]);<?php namespace fast; /*** 字符串类*/ class Http {/*** 发送一个POST请求*/public static …...
网络安全中的数据科学如何重新定义安全实践?
组织每天处理大量数据,这些数据由各个团队和部门管理。这使得全面了解潜在威胁变得非常困难,常常导致疏忽。以前,公司依靠 FUD 方法(恐惧、不确定性和怀疑)来识别潜在攻击。然而,将数据科学集成到网络安全中…...