分布式系统(P2P Lookup)

news2025/2/27 21:51:13

文章目录

  • P2P 系统
    • Napster
    • BitTorrent
    • Gnutella
    • Chord
      • Consistent Hashing
      • Simple Key Location
      • Scalable Key Location
    • Kademlia
      • Routing Table
      • Kademlia’s RPC
      • Adaptability
    • Distributed Hash Table

P2P 系统

Peer to peer 系统:

  • 每个结点在连接上是互联的,在功能上是平等的,在行为上是自由
  • 每个结点既是服务使用者,也是服务提供者
  • 通常构建有高效的覆盖网 (overlay),允许结点动态地加入和离开
  • 每个结点通过冗余机制、周期性检测等,提供容错性

P2P系统的特点:结点自治性,控制分散性,高容错性,高可伸缩性,高可用性,负载平衡

Functional requirements:

  • Locate and communicate with any individual resource:对资源的定位、交互
  • Add new resources or remove them at will:资源的加入、离开
  • Add hosts or remove them at will:主机的加入、离开
  • Provide simple APIs to store and find data:存储、查找数据
    • Typical DHT interface: key with a GUID
    • p u t ( k e y , v a l u e ) put(key, value) put(key,value), g e t ( k e y ) → v a l u e get(key) \to value get(key)value

Non-functional requirements:

  • Global scalability:可伸缩性,可扩展性
  • Load balancing:负载平衡
  • Accommodating to highly dynamic host availability:动态的主机可用性
  • Optimization for local interactions between neighboring peers:与邻居交互的优化
  • Security of data in an environment with heterogeneous trust:数据安全
  • Anonymity, deniability and resistance to censorship:匿名、否认、抵制审查

现有的一些 P2P Overlays:

  • Server-driven,
    • Napster: a music file sharing system
    • BitTorrent: a file sharing system
  • Unstructured,
    • Gnutella: a file sharing system
  • Structured,
    • Pastry, Tapestry: DHT, Prefix routing
    • Chord: DHT, a ring (an artificial one-dimensional space)
    • CAN: DHT, d-dimensional Cartesian coordinate space
    • Kademlia (eMule, BitTorrent without tracker,Ethereum / Block Chain)

Napster

使用方式:

  1. 资源提供方,

    • 用户连接到服务器集群中的一台服务器,把他愿意与其它用户共享的文件信息发送给服务器,服务器根据这些信息和用户的位置,建立索引并加入到原有的索引表中
  2. 资源使用方,

    • 用户发查询请求 Q 给与其相连的服务器,该服务器收到请求后,与其他服务器协作处理查询消息 Q,回复用户一个表单,这个表单包含了所查到的所有匹配的文件索引

    • 用户收到回复 R 后,选择他想要的文件,根据文件索引中对应的位置与其他用户直接建立连接并下载文件

服务器的作用:

  • 维护所有用户的共享文件索引

  • 监控用户的状态

BitTorrent

BitTorrent 由 BT 网站.torrent 文件服务器跟踪器 (Tracker)、BT 用户组成。

  • BitTorrent 中,一个文件分割成固定大小的 (chunk),对应一个 .torrent 文件(种子文件)

    • 文件的名字和长度,下载次数、种子数、上载文件的人
    • Tracker 的位置 (用一个 URL 指定)
    • 与每个块相关的校验和
  • BT 网站 (有一部分种子文件),供用户搜索 .torrent 文件列表

  • Tracker 保存该文件的所有下载者 (downloader) 和种子 (seed) 的注册信息,同时管理多个文件的并发下载

使用流程:用户请求 → \to BT网站 → \to .torrent 文件服务器 → \to .torrent 文件 → \to Tracker → \to 返回下载该文件的 peer 信息,

  • BT 用户与那些 peers 直接相连,进行文件下载 (barter for chunks of the file)

  • 下载同一个文件的用户围绕 Tracker 形成一个独立的子网

BitTorrent 将文件分片 (piece),分片又被划分成子分片,子分片进行流水作业

  • Piece Selection: Rarest First(稀有的分片,首先被传递,防止 peer 退出后失去资源)
  • Piece Selection: Endgame Mode(快完成的文件,被系统竭尽全力地传递,防止功亏一篑)

一报还一报 (tit-for-tat) 的激励机制,

  • 要求 peer 合作,合作,意味着 peer 要上传。不合作的话,就阻塞 peer

  • Peer 本地提供基于 Pareto-efficient 的阻塞算法:每隔一定周期 (10秒) 计算下载率,下载率高的 peer 就不阻塞

  • Optimistic unchoking:每隔一定周期 (30秒) 随机选择一个用户实施不阻塞

在 P2P 系统上使用 Merkle Tree

  1. 校验网络数据的完整性,确保数据块没有损坏
  2. 比较两台机器上文件的异同,发现不一致的副本,减少需传输的数据量

Gnutella

Gnutella协议包含下列消息:

  • Ping,Pong:检查结点是否在线

  • Query,QueryResponse:

    • 文件搜索的洪泛 (Flooding) 策略:每个结点给它的每个邻居转发请求,这些邻居结点再依次把请求传递给它们的邻居,一直到找到匹配的文件为止

    • 每条消息有一个 TTL (time-to-live),以限制洪泛

    • 每个结点缓存最近路由的消息,以支持汇聚 (沿洪泛的反向路径回传消息) ,阻止不必要的重复广播

  • Get,Put:请求获取文件

改进:

  • ((改进1)引入了 Ultrapeer 超级结点:
    1. 超级结点间连接紧密 (每个都有超过32个连接),其他一些对等结点承担叶子结点的角色,
    2. 这大大减少了进行彻底搜索所需求的最大跳数。
  • (改进2)改进了QRP (Query Routing Protocol):
    1. 结点生成 QRT (Query Routing Table),它包含代表结点上的每个文件的 Hash 值;
    2. 接着,发送 QRT 给所有与它相连的超级结点,超级结点基于所有相连的叶子结点的所有项,加上自身包含的文件的项,形成它们自己的 QRT,并与其他相连的超级结点交换 QRT;
    3. 这样,超级结点能对一个给定的查询,决定哪个路径能提供一个有效的路由,从而大大减少了不必要的流量。

Chord

Consistent Hashing

一致性哈希:

  1. 均衡性 (Balance):哈希的结果能够尽可能分布到所有的缓冲中
  2. 单调性 (Monotonicity):当缓冲区大小变化时,应尽量保护已分配的内容不会被重新映射到新缓冲区(Hash 函数与 Buffer 大小无关,类似 x ↦ a x + b ( m o d n ) x \mapsto ax+b \pmod n xax+b(modn) 这种差劲的函数就不要用了,应当使用密码学 Hash 函数!)
  3. 分散性 (Spread):避免由于不同终端所见的缓冲范围有可能不同,从而导致相同内容被映射到不同缓冲区
  4. 负载 (Load):对于一个特定的缓冲区而言,避免被不同的用户映射为不同的内容

将 Hash 空间,组织成虚拟的圆环(长度 m = 32 m=32 m=32 比特的无符号整数),

在这里插入图片描述

  • Node:节点的 GUID 经过 Hash 函数,计算出节点的 Chord Key,这就是这个节点在 ring 上的位置
  • Object:对象的 GUID 经过 Hash 函数,计算出数据的 key 对应的 Chord Key,把它存放在后继的最近的那个 node 上
  • 加入、退出:需要与自己的后继 node 联系,调整这个所的负责的 objects

另外,为了解决数据倾斜,采取虚拟节点机制

在这里插入图片描述

Chord 的特点:

  • Simplicity, provable correctness, and provable performance:简单、可证明正确性、可证明性能
  • 源于一致性哈希算法:
    • Load balance(负载均衡),分布式 Hash 函数,使得 keys 均匀分布在 nodes 上
    • Decentralization(去中心化),完全地分布式
    • Scalability(延展性),查找(lookup)的复杂度仅仅是关于节点数量的对数
    • Availability(可用性),会自动调整 internal tables,确保总是能找到负责某个 key 的节点
    • Flexible naming(灵活的命名),对 keys 的结构没有任何限制,灵活地将 keys 映射到 Chord keys 上

Chord Ring

  1. 使用 SHA-1IP address 做运算,构建一个 m m m 比特的 node’s identifier
  2. 一个 Chord key k k k,被存放到(逻辑上)不比它小的第一个节点上,叫做后继节点 s u c c e s s o r ( k ) successor(k) successor(k)
  3. 一个 Chord key k k k,(逻辑上)比它小的第一个节点,叫做前任节点 p r e d e c e s s o r ( k ) predecessor(k) predecessor(k)

Simple Key Location

一个节点 n n n 查询 i d id id 的定位,直接询问自己的后继 n . s u c c e s s o r n.successor n.successor,函数 n . F i n d S u c c e s s o r ( i d ) n.FindSuccessor(id) n.FindSuccessor(id)

  1. if i d ∈ ( n . i d ,   s u c c e s s o r . i d ] id \in (n.id,\, successor.id] id(n.id,successor.id]
  2. then return s u c c e s s o r successor successor
  3. else return s u c c e s s o r . F i n d S u c c e s s o r ( i d ) successor.FindSuccessor(id) successor.FindSuccessor(id)

正确但低效!

Scalable Key Location

为了加速查找,给予每个节点更多先验知识:Finger Table(将地址空间分区,大小依次为 2 0 , 2 1 , ⋯   , 2 m − 1 2^0,2^1,\cdots,2^{m-1} 20,21,,2m1

  1. 表格 f i n g e r [ 1 ⋯ m ] finger[1 \cdots m] finger[1m] 包含 m m m 项,每一项形如 ( s t a r t , i n t , s u c c ) (start,int,succ) (start,int,succ)
  2. 节点 n n n 上, f i n g e r [ i ] finger[i] finger[i] 记录了信息 ( n . i d + 2 i − 1 ( m o d 2 m ) ,    n . i d + 2 i − 1 ,    s u c c e s s o r ( n . i d + 2 i − 1 ) ) \left( n.id+2^{i-1} \pmod{2^m},\,\, n.id+2^{i-1},\,\, successor(n.id+2^{i-1}) \right) (n.id+2i1(mod2m),n.id+2i1,successor(n.id+2i1))
    • s t a r t start start 记录第 i i i 区间的起始地址
    • s u c c succ succ 记录第 i i i 区间里的第一个节点

在这里插入图片描述

算法为:

  • 函数 n . F i n d S u c c e s s o r ( i d ) n.FindSuccessor(id) n.FindSuccessor(id)
    1. if i d ∈ ( n . i d ,   s u c c e s s o r . i d ] id \in (n.id,\, successor.id] id(n.id,successor.id]
    2. then return s u c c e s s o r successor successor
    3. else
      1. n ′ : = C l o s e s t P r e c e d i n g N o d e ( i d ) n' := ClosestPrecedingNode(id) n:=ClosestPrecedingNode(id)
      2. return n ′ . F i n d S u c c e s s o r ( i d ) n'.FindSuccessor(id) n.FindSuccessor(id)
  • 函数 n . C l o s e s t P r e c e d i n g N o d e ( i d ) n.ClosestPrecedingNode(id) n.ClosestPrecedingNode(id)
    1. for i = m , ⋯   , 1 i=m,\cdots,1 i=m,,1
    2. if f i n g e r [ i ] ∈ ( n . i d , i d ) finger[i] \in (n.id, id) finger[i](n.id,id) then return f i n g e r [ i ] finger[i] finger[i]
    3. return n n n

节点的加入(Join)、退出(Departure),都需要修改 Finger Table,保证记录的 s u c c succ succ 是正确的。

故障恢复:Key step in failure recovery is maintaining correct successor pointers.

  • 每个 node 维护一个后继列表(successor-list),包含 r r r 个最近的后继节点
  • 一旦发现自己的直接后继 fail 了,就使用后继列表中的下一个活结点(the first live entry )取代它
  • 自稳定算法:使得 finger table 以及 successor-list 重新成为正确的

在这里插入图片描述

性能:

  1. 给定 N N N 个 nodes 以及 K K K 个 keys,每个节点负责大约 N / K N/K N/K 个数据。
  2. Lookup 的复杂度仅为 O ( log ⁡ N ) O(\log N) O(logN),因为消息每一跳都距离至少减半。
  3. 当 node 离开或者加入时,只需要换手(keys change hands)大约 N / K N/K N/K 个数据。
  4. 当 node 离开或者加入时,调整 finger-table 以及 successor-list 还有 routing invariants,只需要发送大约 O ( log ⁡ 2 N ) O(\log_2 N) O(log2N) 个消息。

Kademlia

系统中,

  1. 每个结点根据其IP地址及端口分配一个唯一的、随机的 160 160 160 bits 的整数 nodeID
  2. 每个对象被分配一个 key,也是 160 160 160 bits 的整数。
  3. 数据形如 ⟨ k e y , v a l u e ⟩ \langle key, value \rangle key,value,被存放在距离 k e y key key 最近的 nodeID 上。

下面,我们定义结点之间的距离:结点的 nodeID 是 x , y x,y x,y,距离定义为 d i s t ( x , y ) : = x  XOR  y dist(x,y) := x\text{ XOR }y dist(x,y):=x XOR y

  • 非负性: d i s t ( x , y ) ≥ 0 , ∀ x , y dist(x,y) \ge 0, \forall x,y dist(x,y)0,x,y
  • 正定性: d i s t ( x , y ) = 0    ⟺    x = y dist(x,y) = 0 \iff x=y dist(x,y)=0x=y
  • 对称性: d i s t ( x , y ) = d i s t ( y , x ) , ∀ x , y dist(x,y) = dist(y,x), \forall x,y dist(x,y)=dist(y,x),x,y
    • 异或运算是对称的,结点可以从它收到的查询请求中学习到有用的路由信息。
  • 三角不等式: d i s t ( x , y ) + d i s t ( y , z ) ≥ d i s t ( x , z ) dist(x,y) + dist(y,z) \ge dist(x,z) dist(x,y)+dist(y,z)dist(x,z)
  • 单向性:对于任意点 x x x 和距离 d > 0 d>0 d>0,有且仅有唯一的点 y y y,满足 d i s t ( x , y ) = d dist(x,y) = d dist(x,y)=d
    • 单向性保证了对相同数据对象的定位最终将收敛于相同的路径,所以,用 “沿路径缓存” 能提高查找效率、缓解热点。

Routing Table

将所有节点按照 nodeID 组织成一颗二叉树(世界),一个节点对应一个叶子。每个节点都按照距离大小,对世界树进行分块,成为一系列的连续的、不包含自己的子树。

在这里插入图片描述

我们以子树的根节点的路径为子树命名。例如,节点 0011 0011 0011,把世界划分为 1 , 01 , 000 , 0010 1,01,000,0010 1,01,000,0010 四个分块。

然后,每个节点 n n n 维护一个路由表

  1. 包含 160 160 160 项,第 i = 0 , 1 ⋯   , 159 i=0,1\cdots,159 i=0,1,159 项对应一个世界分块,就是以 ( n ⊕ ( 1 ≪ i ) ) ≫ i (n \oplus (1 \ll i)) \gg i (n(1i))i 为树根的那个小世界。
  2. 每一项都是一个大小为 K K K 的列表( K K K 桶),存放这个小世界中的至多 K K K 个随机节点的信息。
  3. 表头:最不经常访问的节点
  4. 表尾:刚访问过的节点

在这里插入图片描述

易知,这些 K K K 桶无交叠地覆盖了整个世界。Kademlia 路由表确保每个节点知道各个子树的至少一个节点。

路由表的维护:捎带更新

  1. 节点 n n n,每当收到来自其他节点 m m m 的信息时,利用它的 nodeID 来更新自己的 K K K
  2. 找到 d i s t ( n , m ) ∈ [ 2 i , 2 i + 1 ) dist(n,m) \in [2^i,2^{i+1}) dist(n,m)[2i,2i+1) 对应的 i : = ⌊ log ⁡ 2 d i s t ( n , m ) ⌋ i:= \lfloor\log_2 dist(n,m)\rfloor i:=log2dist(n,m)⌋,然后维护第 i i i 个桶
  3. 如果桶里已经有 m m m 了,那么就把 m m m 移到尾部
  4. 如果桶里没有 m m m,同时列表长度小于 K K K,那么把 m m m 追加到尾部
  5. 如果桶里没有 m m m,同时列表长度达到 K K K,那么联系表头节点
    1. 如果联系到了,那么把表头移动到到尾部
    2. 如果联系不到,那么删除表头,然后把 m m m 追加到尾部

Kademlia’s RPC

Kademlia 协议的 4 4 4RPC 操作:

  • P i n g ( n o d e I D ) Ping(nodeID) Ping(nodeID):检测节点是否在线
  • S t o r e ( k e y , v a l u e ) Store(key,value) Store(key,value):把数据存储到 P2P 系统里,其中 k e y key key 是 Hash 值
  • F i n d N o d e ( I D ) FindNode(ID) FindNode(ID):获取距离 I D ID ID 最近的 k k k 个节点 ⟨ IP address , UDP port , nodeID ⟩ \langle \text{IP address}, \text{UDP port}, \text{nodeID} \rangle IP address,UDP port,nodeID
  • F i n d V a l u e ( k e y ) FindValue(key) FindValue(key):若消息的接收者曾经收到过 S t o r e ( k e y , ⋅ ) Store(key,\cdot) Store(key,) 指令,那么就返回 v a l u e value value,同时把 ( k e y , v a l u e ) (key,value) (key,value) 存储到据它所知的离 k e y key key 最近的、没有返回 v a l u e value value 的节点中

在这里插入图片描述

F i n d N o d e ( I D ) FindNode(ID) FindNode(ID) 算法,采取连续查询策略:

  1. 查询发起者 n n n 计算距离 d : = d i s t ( n , I D ) d := dist(n,ID) d:=dist(n,ID)
  2. 设置 i : = ⌊ log ⁡ 2 d ⌋ i:= \lfloor\log_2 d\rfloor i:=log2d,从第 i i i 个桶中取出任意的 α \alpha α 个节点 m m m(如果不足 α \alpha α 个,就从附近的桶中选择一些距离接近 d d d 的节点),分别执行 m . F i n d N o d e ( I D ) m.FindNode(ID) m.FindNode(ID)
  3. 那些接收到指令的节点 m m m,首先判断自己是否是 I D ID ID 对应的节点
    1. 如果是,那么回应自己就是最接近的节点
    2. 否则,从桶中选择 α \alpha α 个节点,把这些节点的信息回复给 n n n
  4. 节点 n n n 把这些节点收集起来,找出最近的前 k k k 个节点。如果节点 n n n 没有收到某个节点 m m m 的回复,那么就把它从桶中删除。
  5. 节点 n n n 对于收到的每个节点,继续执行 m . F i n d N o d e ( I D ) m.FindNode(ID) m.FindNode(ID) 操作,直到无法获得更近的 k k k 个节点为止。
  6. 返回这 k k k 个节点。

S t o r e ( k e y , v a l u e ) Store(key,value) Store(key,value) 算法,采取邻近复制策略:

  1. 发布者 n n n 首先执行 F i n d N o d e ( k e y ) FindNode(key) FindNode(key),获得最近的 k k k 个节点 m m m
  2. 然后在这些节点上执行 m . S t o r e ( k e y , v a l u e ) m.Store(key,value) m.Store(key,value),把数据存到这些节点上。
  3. 上述的 k k k 个节点每经过 1 1 1 小时,就重新发布 ( k e y , v a l u e ) (key,value) (key,value),保证数据持续可用。
  4. 而发布者 n n n 每经过 24 24 24 小时,就重新发布 ( k e y , v a l u e ) (key,value) (key,value),否则全部的数据副本都会过期。
  5. 任意一个节点发现了另一个更近的节点 u u u 时,就执行 u . S t o r e ( k e y , v a l u e ) u.Store(key,value) u.Store(key,value),同时并不删除自己保存的数据副本。

Adaptability

Kademlia 网络的自适应性:

  1. 更新:如果路由表的某个 K K K 桶,在 1 1 1 小时内未被查询过,那么就随机选一个 nodeID 执行 F i n d N o d e ( n o d e I D ) FindNode(nodeID) FindNode(nodeID),刷新这个 K K K 桶。
  2. 加入:
    1. 新节点 u u u 加入 P2P 网络,那么联系一个活节点 w w w,把 w w w 放入自己的 K K K
    2. 然后执行 w . F i n d N o d e ( u . i d ) w.FindNode(u.id) w.FindNode(u.id),查询离自己最近的 k k k 个节点,来初始化自己的 K K K
    3. 最后,把自身状态告诉这些节点,以更新它们的路由表
  3. 退出:
    1. 节点不需要发布任何消息
    2. 每个节点周期性地发布自己的数据,把这些数据存放到自己的 k k k 个邻居上

Distributed Hash Table

分布式 Hash 表(DFT):

  • Object key 以及 GUID 使用密码学 Hash 函数来计算
  • 给定带有 nodeID 的节点,把它们组织成一个 ID-Space(1D line/ring, 2D square, tree based on bits, hypercube)
  • 定义规则(rule),把 key 和 nodeID 联系起来(例如把 key 放在最接近的 nodeID 上)
  • 建立路由表,记录自己的邻居(ID-space neighbors)以及远点(farther-away nodes)
  • 对于 N N N 个 nodes 和 K K K 个 keys,高概率负载平衡:
    • 每个节点负责至多 ( 1 + O ( log ⁡ N ) ) ⋅ K / N (1+O(\log N)) \cdot K/N (1+O(logN))K/N 个数据;
    • N + 1 N+1 N+1 个节点加入和离开时,只有 O ( K / N ) O(K/N) O(K/N) 个数据换手。

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

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

相关文章

Spring MVC: 一种简洁且强大的Web应用框架

⭐️前言⭐️ 这篇文章介绍Spring MVC,Spring MVC是现在基本所有Java程序的主流开发框架,这篇文章主要介绍三部分内容: 实现用户和程序的映射(在浏览器输入URL地址之后,能够在程序中匹配到相应方法)。服务器端得到用户的请求参数…

c语言笔记1 输入和输出注意事项,常量 变量 static

输出:printf c的编译器不会检测格式串中转换说明的数量和数据类型是否和后面的变量一致。转换说明的数据类型与实际数据类型不一致时,产生无意义的值。 int 类型的变量length,值为9,输出时将类型写为float或double,输…

【自然语言处理】【ChatGPT系列】InstructGPT:遵循人类反馈指令来训练语言模型

InstructGPT:遵循人类反馈指令来训练语言模型《Training language models to follow instructions with human feedback》论文地址:https://arxiv.org/pdf/2203.02155.pdf 相关博客 【自然语言处理】【ChatGPT系列】InstructGPT:遵循人类反馈…

联想小新pro13 卡顿解决办法

问题 本人电脑型号是 联想小新 pro13 2020 i7 才用了两年多,变得巨卡无比 ctlshiftesc打开任务管理器 cpu利用率才30%多 打字就一顿一顿的出结果 浏览网页也卡的掉帧,更不用说打游戏了 真的很无语,重装了系统也没啥用 思路 在网上搜了一圈…

Linux 网络基础

目录 一.网络 1.重新看待计算机结构 2.几种网络 二.协议 1.协议分层 2.OSI七层模式 3.TCI/IP五层(或四层)模型 三.网络传输 1.网络和操作系统之间的关系 2.网络传输流程图 3.数据包封装和应用 前言:这一篇大体介绍一下网络的一些基础知识。 一.网络 1.重…

do while语句

上次讲了while语句,这次讲一下do while语句。 do...while 循环是 while 循环的变体。在检查while()条件是否为真之前,该循环首先会执行一次do{}之内的语句,然后在while()内检查条件是否为真,如果条件为真的话,就会重复…

王卫点赞友商?北京快递保卫战,顺丰彰显大格局大气度

当下,随着全面放开,国内新冠疫情到了另一个严峻的拐点时刻,特别是北京,正日益逼近感染高峰期。 作为社会生活的毛细血管,快递物流企业们在当下的新冠疫情大背景下上演了一幕幕的鲜活的画面,快递行业市场新…

如何磁盘格式化?分享格式化U盘的3个方法

格式化可以有效管理硬盘,在一定程度上能保证磁盘的性能和使用寿命。尤其是我们遇到一些情况,必须要把U盘进行格式化才行。那么磁盘格式化怎么操作?遇到无法格式化的情况怎么办?别急,下面有3个关于格式化U盘的方法&…

通信协议综述-第3讲 | ifconfig:最熟悉又陌生的命令行

上一节结尾给你留的一个思考题是,你知道怎么查看 IP 地址吗? 当面试听到这个问题的时候,面试者常常会觉得走错了房间。我面试的是技术岗位啊,怎么问这么简单的问题? 的确,即便没有专业学过计算机的人,只要倒腾过电脑,重装过系统,大多也会知道这个问题的答案:在 Win…

图片跟随鼠标移动效果的抖动问题

场景 图片跟随鼠标移动效果的实现思路&#xff1a; 触发mousemove事件响应时&#xff0c;通过e.offsetX,e.offsetY获取到当前鼠标的位置。再修改图片的css样式中的top, left属性&#xff08;图片采用绝对定位&#xff09;。 代码如下&#xff1a; <div id"angel&quo…

车载TBOX嵌入式设备软件的功能测试

作者 | 李伟 上海控安安全测评中心安全测评部总监 来源 | 鉴源实验室 01 Tbox简介 Tbox(Telematics Box)是汽车座舱系统中的一个ECU&#xff0c;物理外观上是一个方正的盒子&#xff0c;通常会有线束接口、HSD接口、通讯和导航天线接口等。软件上Tbox一般会基于Linux操作系统…

音视频面试涨知识(二)

1.YUV知识点 1.1 为什么要有YUV YUV的亮度信号Y和色度信号U/V是分离的&#xff0c;如果只有Y信号分量而没有U/V分量&#xff0c;这样的图像就是黑白灰度图像&#xff0c;从黑白到彩色的兼容方案。 相对RGB&#xff0c;YUV的最大优点是只占用较小的频宽&#xff0c;RGB需要至少…

EasyPytest测试平台开发日志之系统设计

EasyPytest测试平台&#xff0c;帮你高效管理Pytest测试用例。 EP平台的定位是Pytest测试用例管理平台&#xff0c;80%的自动化用例开发在PyCharm等专业的IDE中进行&#xff0c;20%的用例调度和结果查看就交给EP平台来管理。 EP平台是对teprunner测试平台的一次全新升级&#x…

【设计模式】 工厂模式 (三)

文章目录4.2 工厂模式4.2.1 概述4.2.2 简单工厂模式4.2.2.1 结构4.2.2.2 实现4.2.2.4 优缺点4.2.2.3 扩展4.2.3 工厂方法模式4.2.3.1 概念4.2.3.2 结构4.2.3.3 实现4.2.3.4 优缺点4.2.4 抽象工厂模式4.2.4.1 概念4.2.4.2 结构4.2.4.2 实现4.2.4.3 优缺点4.2.4.4 使用场景4.2.5 …

【电脑使用】硬盘无法引导进入系统,无法退出BIOS

前言 因为想要给自己的笔记本添置装备&#xff0c;于是想着把老电脑上的固态拆下来&#xff0c;但是考虑到老电脑虽然不常用&#xff0c;但还是偶尔会用&#xff0c;不能是瘫痪状态&#xff0c;于是想把我之前淘到的一个机械硬盘换上去&#xff0c;结果发现无法引导进入系统&am…

【JavaEE】HTTP(Part1 含面试题)

努力经营当下&#xff0c;直至未来明朗&#xff01; 文章目录前言一、HTTP协议抓包工具协议总格式&#xff08;重要&#xff01;&#xff01;&#xff09;二、HTTP协议中的细节【HTTP请求】【HTTP中的“方法”】【GET】&#xff1a;最常用的HTTP请求【POST】【认识请求“报头”…

SecureBridge Alexandria Release 2和iOS 15的支持

SecureBridge Alexandria Release 2和iOS 15的支持 添加了对Embarcadero RAD Studio 11 Alexandria Release 2的支持。 增加了对Apple iOS模拟器ARM 64位目标平台的支持。 增加了对Lazarus 2.2.2的支持。 添加了对Apple iOS 15的支持。 增加了对Android 12的支持。 SSH、SFTP、…

ubuntu 安装 colmap

目录 一、安装colmap 二、报错解决 三、安装成功 四、colmap使用教程 一、安装colmap 参考安装&#xff1a;​​​​​​​chttps://blog.csdn.net/weixin_46132232/article/details/124211233 官方&#xff1a;COLMAP 官方information 二、报错解决 2.1 在安装colmap的…

HashMap源码解析

HashMap源码解析 基础入门 什么是哈希 核心理论&#xff1a;Hash 也称散列、哈希&#xff0c;对应的英文都是 Hash。基本原理就是把任意长度的输入&#xff0c;通过Hash算法变为固定长度输出。 这个映射的规则就是对应的 Hash 算法&#xff0c;而原始数据映射后的二进制串就…

飞桨VisualDL本地运行问题

最近参加了百度飞桨的基于深度学习的自然语言处理 免费AI课程&#xff0c;有一道作业题是要利用飞桨提供的可视化工具VisualDL查看词向量降维效果。由于安全方面的原因&#xff0c;AI Studio中的可视化服务无法使用了。当按照作业步骤&#xff0c;生成日志文件后&#xff1a; 添…