MIT-6.824-Lab2,Raft部分笔记|Use Go

文章目录

      • 前记
      • Paper6:Raft
      • LEC5、6:Raft
      • LAB2
        • 2A
          • task
          • Hint
          • locking
          • structure
          • guide
          • 设计与编码
        • 2B
          • task
          • Hint
          • 设计与编码
        • 2C
          • task
          • Hint
        • question
        • 后记
      • LEC5:GO, Threads, and Raft
          • go threads技巧
          • raft实验易错点
          • debug技巧

前记

  • 趁着研一考完期末有点点空余时间,把Raft的实验补了
  • 记录着看视频、论文和实验过程中的一些想法

Paper6:Raft

概述(来自NewBing):

raft算法是一种用于分布式一致性的共识算法,旨在解决分布式系统中的领导者选举和日志复制等问题。它的设计目标是易于理解和实现,并且能够提供强一致性保证。raft算法的核心原理包括三个关键组件:领导者选举、日志复制和安全性。

  • 领导者选举:raft算法将时间划分为一个个的任期(term),每个任期的开始都是一次选举,一个或多个候选者(candidate)会尝试成为领导者(leader)。如果一个候选者赢得了大多数节点的投票,它就会成为新的领导者,并在该任期内管理整个集群。如果没有选出领导者,就会开始下一个任期,并重新进行选举。raft算法保证在任意时刻最多只有一个领导者。
  • 日志复制:领导者选出后,就开始接收客户端的请求,并将请求作为日志条目(log entry)加入到它的日志中,然后并行地向其他节点发送附加日志请求(AppendEntries RPC)复制日志条目。当这条日志被复制到大多数节点上,领导者就将这条日志应用到它的状态机,并向客户端返回执行结果。领导者会不断地重试附加日志请求,直到所有的节点都存储了所有的日志条目。
  • 安全性:raft算法增加了一些限制来保证安全性,即只有拥有最新的已提交的日志条目的节点才有资格成为领导者,而且领导者只能提交当前任期的日志条目,旧任期的日志条目要等到提交当前任期的日志条目来间接提交。这样可以避免已提交的日志条目被覆盖的情况。

有一个经验:要想在Raft中假设A情况,你首先得考虑A情况是否有可能发生。

细节点:

  1. Raft Basic

    1. Figure 2是非常重要的一个图。
    2. follower只接受请求,不主动发起请求
    3. 当client发送请求到follower时,会转发给ld处理
    4. ld会通过发送AE来抑制其他server发起选举。也就是说,ld不出错的话,它永远是ld。
    5. 当ld提交时,会通知follower
    6. term会通过包的发送来交换。如果接受者发现有更大的任期,那么它会更新自己的任期。如果发现更小term的包,那么会拒绝。如果ld或candidate发现自己的任期更小了,那么会立刻转变为follower
    7. 时序:client request -> ld -> 将log entry复制到半数以上服务器,并得到回复 -> ld commited、apply -> 返回响应给client ->后面心跳检测(AE)时,随便告诉其他服务器自己已经commited并apply
  2. Leader election

    1. 当election timer计时结束,还没有ld发请求,那么follower会认为ld死了,会变成candicate,发起选举
    2. 如果split votes发生了,那么term会增加,并再次发起选举
    3. timer计时器,是随机的
    4. 注意:每一个新ld的产生,由于它要获得多数server的认可,在请求投票时会把最新的term同步给多数的server!因此term也是一个“多数共识”的标识。
  3. Log replication

    1. 当ld 接收到log entry时,它会保证大多数server都接受到这个log entry,才会继续自己的下一步操作(如返回响应给client)
    2. 如果一个server对接受log entry没有响应,ld会无限地尝试
    3. 如果ld认为LE(log entry)是足够安全的了,那么这个时候叫作committed;注意,apply和committed是不一样的
    4. 在之后,ld会通过AE来将已经committed的index告知给各个follower
    5. 当ld发送AE给follower时,如果follower发现日志冲突,那么ld会decrements nextIndex,直到两者保持一致。注意:ld永远不会重写/删除自己的日志。(decrements nextIndex,不会把follower上的日志删除吗?会的,但是ld一定有了所有能被commited的日志,因此以ld为准。)
  4. Safety

    1. raft保证,被选举出的ld,一定会存有所有已经commited的日志(这个最难理解了。没有commited的entry又怎么处理呢?这样理解,要想commited,那么日志一定是被复制到“半数以上的服务器”。而新ld一定是“半数以上的服务器”中的一个。因此,只要是新ld,那么一定有能保证被commited的日志 。)。:the voter denies its vote if its own log is more up-to-date than that of the candidate。也就是说,要被投票的candidate的日志,要比半数以上的voter的日志要more up-to-date。(什么叫more up-to-date?更大term;如果term相同,则更大index)

      leader的前提是majority,因此leader肯定拥有majority的log(这就是为什么叫做共识)

      上面说法有问题:更正一下:raft保证,被选举出的ld,一定会存有比大多数server更up-to-date的日志

      leader的前提是majority都同意,因此leader肯定拥有majority都同意的更up-to-date的log(这就是为什么叫做共识)

      总结一下:大多数server都认为A服务器有比自己more up-tp-date的log**(共识)**,那么A就可以是ld。

    2. ld只允许commited自己任期内的日志?为什么:

      1. 新ld上线时,不能够确定旧的entry是否已经被commited(如重启后,commitedIndex被重置),旧的entry是否已经被大多数server所有。

        当能commite自己任期内的log entry时,就已经说明前面任期的所有日志一定已经复制到大多数server了。

        因此,只能通过提交自己任期内的log entry,来间接说明之前的日志可以提交。

        同时,能commited自己任期内的日志,说明已经通知到了半数以上服务器,这个时候,半数以上的服务器的日志中的term是和ld一样是最新的。

      2. 图8,描述了,log即使存储在大多数的server上,仍然可能被后面的新ld覆盖(图8的d)。

        因此不能够直接通过复制的数量来判断之前任期的日志条目是否提交(图8的c)。

        所以才出现下下面的解决方案:ld只允许提交自己任期内的log entry。这样保证,当 图8的e 的S1的任期4日志被提交时,任期为3的自然也算被提交了。

  5. Timing and availability:broadcastTimeelectionTimeoutMTBF(平均故障时间)

    1. broadcastTimeelectionTimeout ,如果不能保证这个,那么会频繁出现选举失败
    2. electionTimeoutMTBF,保证这个是因为,让选举平稳进行。这个用脑子想想就知道~,为了保证系统平衡运行,肯定这种定时器要小于故障时间的。
  6. Cluster membership changes

    1. 使用了joint consensus,两阶段转变。首先转为joint状态(中间态),然后再转变为new configuration状态
    2. raft的实现中,在中间态依然可以正常进行选举和处理client的请求
  7. Log compaction

    1. 使用了快照。这个好像在lab3用得到。
  8. Client interaction

    1. 初始时,client会随机挑选一个server进行连接
    2. client发送的请求,都会带有一个 唯一的id
    3. 如果重复请求,那么server会通过请求的id,直接返回之前已经执行过的请求的响应

文章的假设:

  • 应用程序状态是易失的
  • 当一个机器死掉后,通过心跳确认自己的apply位置,并重演一次操作(先不考虑日志压缩)

问题:

  1. 如何避免脑裂?

    1. majority voting system。这个是整个机制的基石
    2. odd servers
    3. 当出现网络partition时,绝不可能有超过一边拥有一半以上的服务器
    4. 大多数投票机制保证:在每一步要投票时,保证投票的“大多数”机器中,一定有一部分会和上次投票重叠。
  2. 如何知道“半数以上”?

    1. raft算法中,每个服务器(节点)都会保存一些关于集群的信息,其中就包括集群的总数目(server count)。这个信息可以在集群初始化的时候,由配置文件或者命令行参数来指定,也可以在集群运行的过程中,由领导者节点来动态更新。
    2. 总数目是固定的,不会因为机器的故障而减少!!!
  3. 要是因网络故障,完全将raft的服务器分区成两半,怎么办?

    1. 绝不可能有超过一边拥有一半以上的服务器
  4. Raft集群最大能忍受的故障server数目是多少?

    1. 假设一共有2f + 1台机器,那么最多允许f台机器故障。底层原理是因为投票机制是多数机制
    2. 如果是有n台机器,那么就是 2f+1=n,f = (n - 1) / 2
  5. 有不确定性操作的命令怎么办?

  6. 为什么需要log entry?

    1. 为了保证操作顺序
    2. 暂存操作。因为操作到来不确定是否一被要执行。
    3. 保存副本,当网络故障时,可以重发给follower
  7. Raft为什么需要要ld?(比如Paxos就没有ld)

    1. 加速系统应答
    2. 让系统更加容易理解
  8. 如果因为网络故障分裂成两个partition,旧ld在一半,但另一半有超过半数的server并且选举出了新ld,这个时候如何处理?为什么旧ld不会导致错误发生?

    1. 因为旧ld不会得到多数server的回应,因此不会成功执行任何命令
  9. 如果一个server的term跑得太快怎么办?

    1. 快就快。有投票机制的保证,没有关系的。
  10. 那么这些entry在旧ld执行后返回给client时失败了怎么办?新上任的ld还会再执行再给返回client吗?

    1. 请求是有带id的,可以通过id来寻找已经执行的结果。
  11. 如果一个ld已经把log复制给大多数server了,但是在commited之前挂掉了。那么这个log算是commited吗?

    1. 还是Figure8©。不算的。只有当前ld将自己任期内的log提交了,之前的所有log才算是commited!
  12. 不能够通过“已经复制日志给大多数server”,来判断“是否已经commited”

    1. 还是Figure8©
  13. 为什么不选有最长日志的,作为领导人?

    1. 最长不代表最up-to-date 。最长不代表能复制给多数server。也就是没有共识。
  14. 什么是线性化语义?

    在Raft协议中,“linearizable semantics”(线性化语义)是一个重要的概念。这意味着,对于任何两个操作,如果在实际执行中,操作A在操作B之前完成,那么在系统的状态中,操作A就应该在操作B之前

    在Raft协议中,为了实现线性化语义,通常会在服务器端维护一个关于已经执行过的请求的记录。这个记录通常包括每个客户端的最后一个请求的ID以及对应的响应。当收到一个新的请求时,服务器首先会检查这个请求的ID是否已经存在于记录中。如果存在,说明这个请求是重复的,服务器就会直接返回之前的响应,而不会再次执行这个请求

    总的来说,"linearizable semantics"是Raft协议中保证一致性的重要机制,它能够确保所有的操作都能按照一定的顺序执行,并且每个操作只执行一次

LEC5、6:Raft

随便记记:

  • mapReduce、GFS、VM-FT都单一实体来决定谁是ld
  • 最详细对raft的资料:https://raft.github.io/
  • 教学动画:https://thesecretlivesofdata.com/raft/

LAB2

注意点:

  1. Raft will continue to operate as long as at least a majority of the servers are alive and can talk to each other. If there is no such majority, Raft will make no progress, but will pick up where it left off as soon as a majority can communicate again.
  2. the service expects your implementation to send an ApplyMsg for each newly committed log entry to the applyCh channel argument to Make()
  3. Your Raft peers should exchange RPCs using the labrpc Go package (source in src/labrpc).:因为测试器会模拟丢包等网络故障
2A

http://nil.csail.mit.edu/6.824/2020/labs/lab-raft.html

task
  1. 实现ld选举 及 心跳检测。当旧ld死掉时(当follower收不到旧ld的心跳时),要有接管机制
Hint
  1. 只关注你当前的任务(但是应该也要考虑到后面的扩展)
  2. 本实验中:the number of Raft peers (usually 3 or 5)
  3. Add the Figure 2 state for leader election to the Raft struct in raft.go.
  4. Modify Make() to create a background goroutine that will kick off leader election periodically by sending out RequestVote RPCs when it hasn’t heard from another peer for a while. This way a peer will learn who is the leader, if there is already a leader, or become the leader itself. Implement the RequestVote() RPC handler so that servers will vote for one another. 就是要有一个机制,心跳超时后要发起选举。
  5. The tester requires that the leader send heartbeat RPCs no more than ten times per second.每秒不得多于10次的心跳检测
  6. 旧ld死掉后,要求5秒内就要完成新ld的选举。因为要求选举时间和心跳间隔选得尽可能短
  7. The paper’s Section 5.2 mentions election timeouts in the range of 150 to 300 milliseconds. Such a range only makes sense if the leader sends heartbeats considerably more often than once per 150 milliseconds. Because the tester limits you to 10 heartbeats per second, you will have to use an election timeout larger than the paper’s 150 to 300 milliseconds, but not too large, because then you may fail to elect a leader within five seconds.(?) 总的来说,这个是说election timer的时间,应该设置超过150~300 milSecond。(gpt建议300到500)。但是不知道原理。。
  8. 使用loop+time.Sleep()来完成周期性任务
  9. You may find this guide useful, as well as this advice about locking and structure for concurrency.
  10. The tester calls your Raft’s rf.Kill() when it is permanently shutting down an instance. You can check whether Kill() has been called using rf.killed(). You may want to do this in all loops, to avoid having dead Raft instances print confusing messages. 就是test发送信号要永久杀死一个server,但是不是通过进程强制杀死。要处理这个信号。周期性任务要通过这个标志判断,是否要继续。
  11. debug:
    1. 可以用print语句,然后使用 go test -run 2A > out. 查看
    2. You might find DPrintf in util.go useful to turn printing on and off as you debug different problems.
  12. 要通过RPC发送的字段,必须大写
  13. 使用go test -race,来保证代码没有race
  14. 测试时间限制: For all of labs 2, 3, and 4, the grading script will fail your solution if it takes more than 600 seconds for all of the tests (go test), or if any individual test takes more than 120 seconds.
locking
  1. 不论读写,如果要保证一致性的,一定要加锁
  2. Code that waits should first release locks. If that’s not convenient, sometimes it’s useful to create a separate goroutine to do the wait.
  3. 等待的代码,要释放锁。但是等待的代码执行完毕后,要重新获得锁,并判断自己的assumption是否还和当前的环境相同(将当时主线程的参数复制到goroutine中)。
structure
  1. 长时间运行的 activities ,应该在不同的线程运行。不同activities 应该也要分割开
  2. 处理timeout的通用思路:存储一个最后时间a,睡眠,然后在某个时间b,判断 b - a > timeout?
  3. 在将log送入到applych时,必须保证顺序。因此这个操作只能在一个goroutine执行
  4. 推进 commitIndex 的代码需要触发应用 Goroutine。为了实现这一点,建议使用条件变量(如 Go 中的 sync.Cond):就是signal机制。
  5. 每个RPC的发送和处理,应该在同一个goroutine.
guide
  1. figure2是绝对权威的总指导

  2. hearbeat返回时,如果返回true,是隐式地告诉ld,当前follower的日志和ld完全同步。因此即使是hearbeat,也要检测里面的term等状态。

  3. 什么时候重置election timer?

    1. 从当前ld接受到AE
    2. 自己开始一个选举期
    3. 投票给其他peer的时候。
  4. 一个任期内,只能投票一次!但是由于这个规则的存在:If RPC request or response contains term T > currentTerm: set currentTerm = T, convert to follower。这会改变当前follower的term,因此可以再次投票

  5. Check 2 for the AppendEntries RPC handler should be executed even if the leader didn’t send any entries. 也就是说,heartbeat应该同正常的AE同等对待。

  6. nextIndex 和matchIndex的不同:

    1. nextIndex:是极其乐观的,初始化为 index+1。ld用来指导FO从哪里开始复制日志
    2. matchIndex:是保守、安全的,初始化为-1。用来指示FO已经复制的最高索引。只有在FO对AE请求返回true时,这个matchIndex才更新。
  7. 对于过期响应的怎么处理:应该在args的参数中保留你发送时的term,然后在返回响应时,比较当前term和当前发送的term是否一样。如果不一样,直接丢了。

  8. matchIndex的更新:如果在收到响应后,已经check过assumption了,那么应该将matchIndex=prevLogIndex+len(entrites[]),而不是直接 matchIndex=nextIndex-1 or matchIndex = len(log)。因为在发送请求的期间,nextIndex可能已经改变了(比如故障重启),len(log)更会改变,比如有Client请求拼接。

  9. 快速恢复的nextIndex:https://thesquareplanet.com/blog/students-guide-to-raft/#an-aside-on-optimizations

    在AE的reply时,返回多两个字段:conflictIndex和conflitTerm

    1. 如果FO没有prevLogIndex的日志,那么直接返回 conflictIndex=len(FO自己的所有log), conflictTerm=None
    2. 如果FO有prevLogIndex的日志,但是term不匹配(设FO的冲突的Term为termA)。则返回 conflictTerm=log[prevLogIndex].Term=termA。并把 conflictIndex设置为termA的第一个log
    3. 当LD收到冲突响应时,首先查找自己是否有 conflictTerm=termA的日志。如果有,将nextIndex设置为termaA的最后一个日志的下一个位置。
    4. 如果没有termA的日志,则直接将nextIndex=conflictIndex

    简单折中实现就是只用conflictIndex不用conflictTerm,但这样在某些情况下会多发送些log entry。

    conflictIndex的作用:

    • 跳过所有FO自己没有的日志
    • 跳过一个term的日志(这里就是把所有冲突的termA全部跳过)

    conflitTerm的作用:

    • 辅助,让 LD 的nextIndex不要把所有的termA日志都跳过
  10. If the leader has no new entries to send to a particular peer, the AppendEntries RPC contains no entries, and is considered a heartbeat. 也就是说,同步日志的频率至少和hearbeat一样!或者说,直接把同步日志这个功能做成heartbeat。如果有需要同步的日志,那么直接同步。如果没有需要同步的日志,则看成是一个heartBeat(entries=null)。

    遇到的问题:在hearbeat实现的时候,没有按AE的规则来严格设置prevLogIndex和相应的entries[],导致一些bug出现。比如一个hearbeat过来,带了最新的leadercommit,把FO的rf.commit更新了,但hearbeat并没有携带最新的log。

    因此,在实现的时候,直接把同步日志做成心跳检测。逻辑上统一了。并设置条件变量,在需要的时候手动触发一次同步日志。(也就是设置死循环,用和heartBeat一样的频率触发这个条件变量。然后这个条件变量也可以在其他地方手动触发)

    所以是把 AE看成是hearbeat… 有点奇怪的感觉

设计与编码

有哪些周期性activity:

  1. ld的心跳检测
  2. FO的election timeout

要加哪些额外的状态?

  1. 当前ld的id

动作有哪些?

  1. ld发送心跳
  2. FO变成CA,并发起选举,请求多数投票
  • 被killed()了,那么剩下的已经启动的goRoutine怎么办?难道说每一个动作后面都要加killed()判断?,那也太麻烦了吧。目前看来,只要在各个函数头加上killed()判断就行,即使剩下的go routine被执行了,也不会造成实质性的伤害。 然后每一个动作后加上killed()判断,更直观点,毕竟killed()也是assumption之一。
  • 注意:rf.dead变量虽然是原子的,但这种原子性是为了保护这个变量。所以判断killed()的时候,最好也当成关键性代码,用mutex包裹起来。
  • 小心!defer如果放在一个死循环里面,会执行不了!
2B
task

Implement the leader and follower code to append new log entries, so that the go test -run 2B tests pass.

Hint
  1. 实现Start()函数拼接日志,并同步
  2. One way to fail to reach agreement in the early Lab 2B tests is to hold repeated elections even though the leader is alive. Look for bugs in election timer management, or not sending out heartbeats immediately after winning an election
设计与编码
  1. 当service调用Start()时,拼接日志到log[],signal条件变量cond1
  2. 当ld的 last log index >= nextIndex时,要发送同步日志 syncLogToPeer。成功则更新nextIndex和matchIndex。失败的话,减少nextIndex,继续尝试,signal一下条件变量cond1。然后刚成为LD的时候,应该也要启动一下这个。
  3. 如何确认能commited?当 N > commitIndex,并且N大于大多数的matchIndex,并且log[N].term == rf.currentTerm,那么就能commit到这里。什么时候检查?先定期吧,简单点。
2C
task
  1. Complete the functions persist() and readPersist()
  2. Insert calls to persist() at the points where your implementation changes persistent state
Hint
  1. You will probably need the optimization that backs up nextIndex by more than one entry at a time
question

实现中疑惑的点:

  • 同步日志的时候,如果用条件变量来实现,那么当一个server crash的时候,没有时机去触发这个条件变量。后面我还是用了for+sleep来实现。有什么好的办法?
  • 条件变量的用处似乎不大?因为都是周期性任务。而且如果用触发来做,有些情况又触发不了。不过实现的时候,apply log用了条件变量。这个是一定可以被触发的。
  • 代码中还有比较多的todo偷懒没搞hh,那些都是可以优化的点
后记

全部代码写完后,重新运行三个test。均通过。

由于1次实验有偶然性,再运行10次 go test -run 2,也均通过。(要多运行几次,小概率的bug才会出现)

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  1. 写代码前,还是得弄清楚需求(这里是看大量lab相关的文档)。写代码加调试花了2~3天(周日下午到周三早上,期间还帮师兄改了论文),但看论文和文档远远不止。

  2. 写完后,看了别人的代码,差别还是挺大的hh,自己实现得比较乱,别人可以这么优雅

  3. 而且要遵守建议和论文中的规则,自己创造性地“乱写”(没有被证明对),那么debug之路会很漫长

  4. RPC调用与assumption

  5. 日志索引从1开始,确实很妙,省去了非常多的代码判断。

LEC5:GO, Threads, and Raft

  1. 在写实验的时候,用大粒度锁就行,别trick.去想着从cpu层面优化~
  2. The Go Memory Model:If you must read the rest of this document to understand the behavior of your program, you are being too clever. Don’t be clever.
  3. 如果你的代码中出现了常数,要想想为什么可以是常数?为什么是这个常数,其他常数不行?
go threads技巧

waitGroup、闭包(能访问到创建该线程的上下文)

//1.可以作为投票的一种实现
func main() {var wg sync.WaitGroupfor i := 0; i < 5; i++ {wg.Add(1)go func(x int) {sendRPC(x)wg.Done()}(i) //2.i要传递}wg.Wait()
}func sendRPC(i int) {println(i)
}

周期性任务

func periodic() {for {println("tick")time.Sleep(1 * time.Second)mu.Lock() //如果不加锁,无法保证能马上见到其他人作的改变if done {return}mu.Unlock()}
}

条件变量 (signal):建议实验中直接用broadcast

func main() {rand.Seed(time.Now().UnixNano())count := 0finished := 0var mu sync.Mutexcond := sync.NewCond(&mu)for i := 0; i < 10; i++ {go func() {vote := requestVote()mu.Lock()defer mu.Unlock()if vote {count++}finished++cond.Broadcast()}()}mu.Lock() //注意。要先获得lock才能wait。相当于java中,synchorized 这个功能放进了Object中了for count < 5 && finished != 10 {cond.Wait()}if count >= 5 {println("received 5+ votes!")} else {println("lost")}mu.Unlock()
}func requestVote() bool {time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)return rand.Int() % 2 == 0
}
mu.Lock()
// do something that might affect the condition
cond.Broadcast()
mu.Unlock()----mu.Lock()
while condition == false {cond.Wait()
}
// now condition is true, and we have the lock
mu.Unlock()

channel(无缓冲channel):

  • 是一种没有容量的队列。当发送时,如果没有接收方,发送线程会被阻塞。相反地,如果没有人发送,接收方也会被阻塞
  • 可用于生产者消费者
  • waitGroup效果
func main() {done := make(chan bool)for i := 0; i < 5; i++ {go func(x int) {sendRPC(x)done <- true}(i)}//和waitGroup的效果一样for i := 0; i < 5; i++ {<-done}
}func sendRPC(i int) {println(i)
}
raft实验易错点
  1. 不应该在调用RPC时,持有锁。1影响效率,2容易死锁。可以通过传递assumption消除
debug技巧
  1. cirt + /,可以打印堆栈

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

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

相关文章

软考29-上午题-【数据结构】-排序

一、排序的基本概念 1-1、稳定性 稳定性指的是相同的数据所在的位置经过排序后是否发生变化。若是排序后&#xff0c;次序不变&#xff0c;则是稳定的。 1-2、归位 每一趟排序能确定一个元素的最终位置。 1-3、内部排序 排序记录全部存放在内存中进行排序的过程。 1-4、外部…

微信小程序 --- wx.request网络请求封装

网络请求封装 网络请求模块难度较大&#xff0c;如果学习起来感觉吃力&#xff0c;可以直接学习 [请求封装-使用 npm 包发送请求] 以后的模块 01. 为什么要封装 wx.request 小程序大多数 API 都是异步 API&#xff0c;如 wx.request()&#xff0c;wx.login() 等。这类 API 接口…

【精选】Java面向对象进阶——内部类

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏 …

【操作系统】磁盘文件管理系统

实验六 磁盘文件管理的模拟实现 实验目的 文件系统是操作系统中用来存储和管理信息的机构&#xff0c;具有按名存取的功能&#xff0c;不仅能方便用户对信息的使用&#xff0c;也有效提高了信息的安全性。本实验模拟文件系统的目录结构&#xff0c;并在此基础上实现文件的各种…

FISCO BCOS(十七)利用脚本进行区块链系统监控

要利用脚本进行区块链系统监控&#xff0c;你可以使用各种编程语言编写脚本&#xff0c;如Python、Shell等 利用脚本进行区块链系统监控可以提高系统的稳定性、可靠性&#xff0c;并帮助及时发现和解决潜在问题&#xff0c;从而确保区块链网络的正常运行。本文可以利用脚本来解…

Vue3 使用动态组件 component

component 标签&#xff1a;用于动态渲染标签或组件。 语法格式&#xff1a; <component is"标签或组件名">标签内容</component> 动态渲染标签&#xff1a; <template><h3>我是父组件</h3><component is"h1">动态…

SpringCloud(15)之SpringCloud Gateway

一、Spring Cloud Gateway介绍 Spring Cloud Gateway 是Spring Cloud团队的一个全新项目&#xff0c;基于Spring 5.0、SpringBoot2.0、 Project Reactor 等技术开发的网关。旨在为微服务架构提供一种简单有效统一的API路由管理方式。 Spring Cloud Gateway 作为SpringCloud生态…

【Unity】MySql +Navicat 安装教程

问题描述 在使用Unity开发的时候&#xff0c;有的时候我们是需要使用Mysql数据库的&#xff0c;本教程使用的MySql 和Navicat均为免安装版 ❶mysql安装 1.下载mysql解压至任意目录&#xff0c;此处以“C:\mysql-5.6.39-winx64”为例. mysql百度云连接&#xff1a; 链接&…

Java的递归【详解】

1.认识递归基础知识 什么是方法递归&#xff1f; 递归是一种算法&#xff0c;在程序设计语言中广泛应用。 从形式上说&#xff1a;方法调用自身的形式称为方法递归&#xff08; recursion&#xff09;。 递归的形式&#xff1a; 直接递归&#xff1a;方法自己调用自己。 间接递…

【监控】Spring Boot+Prometheus+Grafana实现可视化监控

目录 1.概述 2.spring actuator 3.Prometheus 3.1.介绍 3.2.使用 1.client端的配置 2.server端的配置 4.grafana 5.留个尾巴 1.概述 本文是博主JAVA监控技术系列的第四篇&#xff0c;前面已经聊过了JMX、Spring actuator等技术&#xff0c;本文我们就将依托于Spring …

利用docker一键部署LLaMa到自己的Linux服务器,有无GPU都行、可以指定GPU数量、支持界面对话和API调用,离线本地化部署包含模型权重合并

利用docker一键部署LLaMa到自己的Linux服务器,有无GPU都行、可以指定GPU数量、支持界面对话和API调用,离线本地化部署包含模型权重合并。两种方式实现支持界面对话和API调用,一是通过搭建text-generation-webui。二是通过llamma.cpp转换模型为转换为 GGUF 格式,使用 quanti…

Leetcode日记 889. 根据前序和后序遍历构造二叉树

Leetcode日记 889. 根据前序和后序遍历构造二叉树 给定两个整数数组&#xff0c;preorder 和 postorder &#xff0c;其中 preorder 是一个具有 无重复 值的二叉树的前序遍历&#xff0c;postorder 是同一棵树的后序遍历&#xff0c;重构并返回二叉树。 如果存在多个答案&#…

petalinux_zynq7 驱动DAC以及ADC模块之二:petalinux

petalinux_zynq7 C语言驱动DAC以及ADC模块之一&#xff1a;建立IPhttps://blog.csdn.net/qq_27158179/article/details/136234296在上一篇&#xff0c;建立了ADC和DAC两个IP。这里继续。本文在 petalinux默认配置的基础上&#xff0c;添加了python和qt。再编译出sdk可以给x86主…

汽车智能座舱中 显示屏市场战略趋势分析 中篇

今天主要讲讲主流车厂显示屏的趋势。 主流车厂的中控&液晶仪表屏的尺寸及趋势汇总 奔驰 奔驰A级 10.2510.25 奔驰C级 12.310.25 奔驰GLA 10.2510.25 奔驰E级 12.312.3 奔驰S级 12.312.8 1、奔驰的仪表几乎都为液晶仪表&#xff0c;几乎所有车型都有HUD的选配&#xff…

大功率应用中的厚膜电阻散热器的设计?

在许多大功率应用中&#xff0c;例如电机和电源&#xff0c;电源电阻器位于主电源线中。它们的目的是防止损坏或提供一定程度的控制。 在这些应用中&#xff0c;电阻器承受恒定的、相对较高的电流。当电流流过电阻器时&#xff0c;它会产生热量。这种热能必须消散到环境中&…

1、WEB攻防-通用漏洞SQL注入MYSQL跨库ACCESS偏移

用途&#xff1a;个人学习笔记&#xff0c;欢迎指正&#xff01; 前言&#xff1a; 为了网站和数据库的安全性&#xff0c;MYSQL 内置有 ROOT 最高用户&#xff0c;划分等级&#xff0c;每个用户对应管理一个数据库&#xff0c;这样保证无不关联&#xff0c;从而不会影响到其他…

Autosar-WdgM配置详解-3

1.11生成代码解析 1.11.1MasterSWC代码解析 在MasterSWC的RE_TestRun这个runnable里会调用两个检测点函数,我们可以在两个检测点函数之间,加入我们所需要监控的代码。 Rte_Call_RPort_StartCheckPoint_CheckpointReached(); Rte_Call_RPort_EndCheckPoint_CheckpointReac…

C#串口 Modbus通讯工具类

一、安装Modbus包 二、创建modbushelper类 1、打开串口 public bool IfCOMOpend; //用于实例内的COM口的状态 public SerialPort OpenedCOM;//用于手动输入的COM转成SERIAL PORT /// <summary> /// 打开串口 /// </summary> /// <param name="COMname&quo…

c++服务器开源项目Tinywebserver运行

c服务器开源项目Tinywebserver运行 一、Tinywebserver介绍二、环境搭建三、构建数据库四、编译Tinywebserver五、查看效果 Tinywebserver是github上一个十分优秀的开源项目&#xff0c;帮助初学者学习如何搭建一个服务器。 本文讲述如何在使用mysql跟该项目进行连接并将项目运行…

python 层次分析(AHP)

文章目录 一、算法原理二、案例分析2.1 构建指标层判断矩阵2.2 求各指标权重2.2.1 算术平均法&#xff08;和积法&#xff09;2.2.2 几何平均法&#xff08;方根法&#xff09; 2.3 一致性检验2.3.1 求解最大特征根值2.3.2 求解CI、RI、CR值2.3.3 一致性判断 2.4 分别求解方案层…