深入浅出 -- 系统架构之分布式多形态的存储型集群

一、多形态的存储型集群

在上阶段,我们简单聊了下集群的基本知识,以及快速过了一下逻辑处理型集群的内容,下面重点来看看存储型集群,毕竟这块才是重头戏,集群的形态在其中有着多种多样的变化。

逻辑处理型的应用,部署集群架构是为了解决单点故障、获得更高的吞吐量,集群内各节点之间没有依赖关系,同时遵循着“去中心化思想”,即多个节点里没有所谓的“老大”。

反观存储型的应用,需要保存数据、记录会话数据、用户认证信息、事务状态等信息,如果要搭建集群架构,则需要考虑各节点之间的数据一致性和完整性,来看个例子:

假设现在数据库使用三个节点组成集群,如果和业务系统集群一样,多个节点之间地位平等,此时客户端读写数据时,究竟该去到哪个节点呢?包含多个操作的事务如何保证落到同一节点?用户在A节点登录后,如何把登录态(连接信息)同步给B、C节点?

正是因为上述一堆的问题,存储型集群里的节点必须要划分等级,一定要有一个等级更高的节点,来承担客户端的写操作。因此,在很长一段时间内,涉及到数据存储的应用,集群方案都是以主从模式为主。

趣事:主从模式对应的英文是Master/Slave,不过大家会发现,后来许多技术的主从模式,都叫Leader/Follower,这是为啥?因为Master/Slave代表的是“主人/奴隶”,再加上集群存在选举机制,所以在西方被痛斥为“此命名的政治思想不正确”,于是许多技术栈都经历过“语言净化”(如Redis)……

好了,上面提到主从集群,下面来展开聊聊存储型应用的集群方案,粗分下来也是两大类:

主从模式:集群内的节点区分等级,可以有一或多个主节点,具备完整的读写能力;也允许拥有多个从节点,但能力方面有所阉割,只具备处理读取请求的能力。

分片模式:集群内节点地位平等,各节点都具备数据读写能力,但每个节点只负责一部分数据,完整数据分散在各节点上。

1.2、主从架构

主从集群,这个概念所有人都熟悉,它的身影在各种技术栈随处可见,如主从集群、镜像集群、复制集群、副本集群……,尽管在不同技术栈的叫法不同,可本质上都是同一个东西。

上图是经典的一主多从架构,客户端的写请求,都会落到主节点A上,而后再给同步给B、C这两个从节点,这就是大名鼎鼎的“主从复制技术”,数据同步有三种方案:

  • 同步复制:等数据写入集群所有节点后,再给客户端返回写入成功;
  • 半同步复制:等集群内一半数量以上的节点写入数据成功后,给客户端返回写入成功;
  • 异步复制:数据在主节点上写入成功后,立即给客户端返回写入成功。

大多数支持主从复制的技术栈,几乎都上面三种同步方案,从数据一致性角度看:同步复制>半同步复制>异步复制,而从性能角度出发则完全相反:异步复制>半同步复制>同步复制

如今大多数技术栈默认的复制方案都是第三种,虽然有数据丢失的风险,可是它的性能最好,何况“主节点写入完数据,正好就发生故障”的这种几率很小。当然,如果你的系统更在乎数据一致性和安全性,那就可以选择半同步模式,如果完全不在乎性能,则可以切换成同步复制模式。

1.2.1、读写分离

在主从架构中,因为从节点被阉割掉了处理写请求的能力,所以在大部分时间里,如果从节点只作为数据副本而存在,显然会造成很大的资源浪费。为了充分利用从节点的资源,一种名为“读写分离”的技术曾风靡一时。

虽然从节点没有处理写请求的能力,可是它会把主节点写入的所有数据都同步过来,为此,它具备“一定程度”的读请求处理能力,此时就可以将读取数据的请求分发给从机,既能充分利用空闲资源,又能减轻主节点的访问压力

PS:从节点只具备“一定程度”的读请求处理能力,注意里面用引号标出的“一定程度”,这啥意思?

因为主从复制技术,都依靠网络来同步数据,而网络并不可靠,也必然存在延迟性。在异步复制的模式下,当一个数据写入到主节点,立马出现读请求到从节点读取,此时有可能读不到最新的数据。

1.2.2、故障转移

本文开篇提到的集群四大优势,其中一条则是保证了高可用,解决了单点故障问题,可实际上部分技术栈,虽然支持主从集群,但却只提供了基本的主从复制功能(如MySQL),并不具备故障转移能力。

所谓的故障转移,通常是针对主节点而言的,即:当主节点发生故障时,集群能自动推选出新主节点,并将流量自动转移到新主处理。大家熟知的MySQL,它并不具备自动故障转移功能,当原本设定的主节点故障后,必须通过人工介入、或第三方工具(如MHA),又或者自己研发的组件实现故障转移。

当然,也有很多技术栈,官方就实现了故障转移机制,比如RedisSentinel哨兵、MongoDBArbiter仲裁者、KafkaController控制器……,这些中间件的主从集群,在主节点发生故障时,都能实现无人力介入、自动转移效果。

这种自动故障转移机制,它们内部是如何实现的?其实原理大同小异,故障转移的第一步,是需要能检测出故障的节点,有两种方案可选:

  • ①探测模式:负责故障处理的节点,每隔一段时间向集群所有节点发送探测包(ping),没有回复的节点说明已经故障;
  • ②上报模式:集群内所有节点,主动向负责故障处理的节点发送存活信息(心跳),当一个节点没有心跳时说明陷入故障。

不过为了兼容网络分区问题,通常会组合起来使用,正常情况下,集群节点主动发送心跳包,当某个节点没有心跳后,故障处理节点会主动发起探测请求,如果还是没有回复,则会认为该节点陷入故障。考虑到网络分区的影响,故障处理节点也可能陷入了分区,因此也会向其他故障处理节点,发出二次确认的请求,以此进一步确认对应节点是否故障。

PS:上述概念类似于Redis哨兵里的主观下线、客观下线,同时也不仅仅只有故障处理节点,具备故障检测能力,集群内的节点也拥有该能力,如从节点去拉数据时,也可以检测出主节点的健康状态。

如果本次检测出的故障节点是主节点,则会进入新主选举流程,选举一般是通过投票机制实现,新主上任的前提是“节点数一半以上的票数”;而投票机制的内在逻辑则是数据POS点,即谁的数据更新则更有机会成为新主,总体流程如下:

  • ①故障检测:当感知到某个节点不可用时,会先发起通信向其他可用节点进行二次确认;
  • ②故障处理:如果检测到主节点不可用,从节点会将自己转换为候选人,并向其他成员宣布;
  • ③选举开始:轮次号加一,开启一轮新的选举,每个候选人节点开始向其他成员发送拉票请求;
  • ④投票开始:在一个新的选举轮次中,每个节点只能投一票,可以投给自己或者其他节点;
  • ⑤投票结束:所有节点已投票,或抵达本轮选举的时间限制后,将获得大多数投票的节点立为新主;
  • ⑥主从切换:新主会向其他节点发送“上位”消息,其他节点更新自己的配置,接受新主上位;
  • ⑦数据同步:完成主从切换后,从节点以新主为数据基准,校验自身数据是否完整,有缺失则同步。

上面只是大概流程,但几乎所有技术栈实现的思路都是这样,因为它们都遵循着Paxos、Raft等协议制定的标准,本文对此不做展开,后续会单开篇章来聊。

1.2.3、级联复制

级联复制是主从架构的变种,其本质还是主从模型,主要用于一主多从的结构中,如:

在主从架构中,想要实现数据同步有两种方式:

  • 主节点推送:当主节点出现数据变更时,主动向自身注册的所有从节点推送新数据写入。
  • 从节点拉取:从节点定期去询问一次主节点是否有数据更新,有则拉取新数据写入。

但不管是哪种方式,都会存在一个问题:主节点同步数据的压力,会随着从节点的数量呈线性增长!啥意思?因为不管是推还是拉,数据都需要从主节点出站。

对主节点来说,数据同步会对磁盘、内存、带宽、CPU带来不小压力,此时多一个从节点,自然多出一倍的压力,数据量较大时,特别容易把主节点的资源占满,从而造成主节点无法处理客户端的请求,级联复制的出现,就是为了解决此问题。

级联复制模式中,只有一个从节点B挂在主节点A下面,其余的从节点都会成为B的从节点,数据由B先同步到自身,其余节点再从B去同步数据,这样就解决前面的问题,可此时又会带来新问题:

  • 数据延迟:本身主从复制就存在延迟性,而新加入一层后,数据延迟性会更高;
  • 级联节点故障:负责同步主节点数据的B一旦故障,会导致其余从节点无法同步数据。

凡事有利必有弊,虽然级联复制能解决原本的问题,可是也会带来新问题,这时就需要处理新的问题,或者把新问题的影响降到最低。

PS:用来同步数据的Canal中间件,就类似于级联复制的思想。当然,除开小部分特殊的项目,一般很少用到级联复制模式。

1.2.4、多主热备

虽然可以通过读写分离、级联复制,减轻主节点的部分压力,可对于写请求,都必须得落到主节点上处理,而主节点再强悍,总有扛不住的时候,这时又出现了变种集群:双主/多主模式

多主模式也是建立在主从复制的基础之上,比如双主模式时,两个节点互为主从,各自都具备完整的读写能力,客户端的写请求,可以落入任意节点上处理。不管数据落到哪个节点,另一个节点都会将数据同步过去,此时客户端的读取请求,在任意节点上都能读到数据。

通过这种方案,可以将写入性能翻个倍,并且可以继续拓展出更多的主节点,组成多主集群。不过一般是双主,因为大部分技术栈支持的主从集群,仅允许为一个从节点配置一个主节点,在这个限制下,想要实现多主,则只能组成环形多主集群:

这种环形多主架构,由于每个节点都支持写入数据,所以能极大提升写入吞吐量,但成也萧何败也萧何,一个节点写入新数据后,需要经过N次(节点数量-1)复制,才能将数据同步给所有节点,集群内的延迟性很高,这也是为什么一般只搭建双主的根本原因。

PS:多主集群除开能提升写入吞吐量外,只要客户端略加适配,就可以实现“客户端版故障转移”,即客户端检测到一个节点不可用后,自动切换到其他节点上读写数据。

1.3、分片架构

不管是开始提到的横向集群,还是上面聊到的主从集群,本质上都是“克隆”多个具备完整功能的单机节点组合部署,尽管主从里的从节点功能有所阉割,可整体上还是属于主节点的复制体。

对业务系统这类应用而言,用多个克隆体组成集群没任何问题,这也是集群概念的标准思想,但对于存储型应用来说,就会出现三个致命问题:

  • 木桶效应:三个节点的磁盘容量为512G、1T、1T,集群最大容量则为512G
  • 写入受限:传统的主从集群,写入的吞吐量受单个主节点限制,写入的并发很难提升;
  • 容量危机:主从集群通过升配存储GB、TB级数据,但上升到PB甚至更高量级时无力。

为了解决木桶效应,必须保证集群所有节点的资源配置一致,否则同步数据时存不下;为了解决写入受限,可以搭建另类的多主集群,可这种模式数据延迟太大;为了存储海量数据,只能不断加硬件资源带来更大的存储空间……

主从集群有着天然的弊端,虽然可以通过特殊手段环境,但无法根治“先天性的劣势”,这种传统型的集群方案,不再适用于增长迅猛的系统(无法处理高并发与海量数据存储)。正因如此,存储型应用在设计集群模式时,做出了一个违背祖宗的决定:将数据分区存储,既然一台机子存不下,那我就用多台机子存!

1.3.1、分片式集群

分区存储,就是目前大数据存储领域大名鼎鼎的分布式存储技术,也叫:分片式集群,我们再来好好聊聊这块知识~

之前的单体模式也好,主从集群也罢,数据其实都是集中式存储,即所有数据都存储在一起。分区存储,就相当于把原本的一缸水,分到不同的桶子里,如下:

每个分片节点,都具备读写数据的能力,这样就从根本上解决了写入瓶颈,并且数据分散到多个节点独立存储,这并不受木桶效应的影响,解决了PB级数据存储造成的容量危机。

分片集群的好处很多,但想要实现分片式存储,首先要解决的就是数据路由问题,写入时能自动根据规则落到某个分片节点存储,读取时能精准找到存储的分片节点获取数据。这和前面聊的请求分发算法类似,只不过数据分发时,需要保证同一数据的写入/读取落入相同的节点。

数据路由到具体的分片节点,有两个核心点,一是分片(路由)算法,二是分片(路由)键。数据分发和请求分发不同,因为要保证同一数据读写都在相同节点操作,光靠分发算法无法实现,所以每条数据需要有个标识,这个标识就是路由键,以ID字段作为路由键来举例:

集群有四个节点,选用取模分发算法,根据ID值取模节点数量,计算出数据最终要落入的节点。来看实际过程,假设要操作ID=1这条数据:

  • 写入:路由键ID取模四:1%4,结果为1,数据落入分片节点2
  • 读取:路由键ID取模四:1%4=1,从分片节点2中读取数据。

通过这种方式,就保证了读写数据的节点一致,避免“写入成功,无法读取”的尴尬现象发生。不过除了取模分发外,还有其他一些分发算法,如范围分发、哈希取模、一致性哈希、哈希槽……,像Redis-cluster集群中,就采用CRC16算法计算KeyKey即路由键),并结合哈希槽模式实现数据分发。

解决了数据分发问题后,分片架构其实还存在一系列问题,好比多节点的数据如何聚合等等。如果当前分片的存储组件属于关系型数据库,如何兼容事务机制?多表联查如何关联?如何实现多字段维度查询?当然,其实还有一系列头疼的问题,这里不做展开,感兴趣可参考《分库分表副作用篇》。

经过上面的阐述后,大家一定对分片式集群有了基本认知,现在来聊聊分片集群的类型,总体可分两种:中心代理分片集群、去中心化分片集群

1.3.2、中心化分片集群

中心化分片集群,意味着集群中又存在不同的角色节点,最少有两种:

  • 中心节点:负责路由规则、数据节点的管理工作,以及处理数据分发请求,自身不存储分片数据;
  • 数据节点:具体存储数据的分片节点,负责处理中心节点分发过来的写入/读取数据请求。

上面的中心节点,就类似于之前的”负载均衡器“,负责管理集群所有节点,以及具体的分发工作,这种模式也是早期最主流的分片集群方案,即:代理式分片集群

代理式分片,可以在官方不支持分片集群的情况下,自己来搭建分片集群,以传统关系型数据为例,MySQL官方并不支持分片存储,怎么办?如果工作年限较长的小伙伴一定清楚,之前有个大名鼎鼎的中间件叫:MyCat,示意图如下:

尽管MySQL不支持分片架构,但通过上述方案,可以将一个个独立的MySQL节点,组合成一个逻辑上的大整体,每个独立的MySQL节点,则代表着具体要存储数据的分片节点。MyCat则是负责节点管理与数据分发的中心节点,所有要操作MySQL的客户端,都会连接到MyCat,读写请求交给MyCat做具体分发。

PS:实际MyCat就是伪装成了一台MySQL,业务系统依旧和往常一样连接即可,屏蔽了客户端对分片集群的感知。

除开MyCat外,如同类型的Sharding-Proxy,又或者早期RedisTwemProxy、Codis等等,这都是代理式分片理念的产物。究其根本,还是由于早期官方并不支持分片式架构,因此部分业务庞大的企业迫于无奈,只能在更高的维度上,架设中心节点来分发数据到不同的节点中存储。

这种中心化分片集群的思想,直到现在依旧在使用,只不过如今很少有代理中间件,基本都由官方自己实现,如MongoDB分片集群,依靠路由节点mongos进行数据分发。

为啥我称呼这类分片集群为“中心化分片集群”呢?其实站在数据/分片节点的角度出发,节点之间相互平等,不存在之前主从架构里的Master概念。可是,虽然没有了Master,但在数据节点之上有了一种更高维度的节点,所有数据节点都得“听”它安排,这就是一种另类的中心化体现。

中心化分片集群有何劣势?特别明显,不管是第三方实现的代理中间件,还是官方自身研发的“高等级节点”,毕竟所有请求都需经过“中心节点”,为此,一旦这类节点故障,必然会造成整个分片集群不可用。

中心化分片集群,为了解决中心节点的单点故障问题,一般都需要对中心节点做高可用建设,如mongos集群式部署、MyCat做热备等等。

1.3.3、去中心化分片集群

与上阶段提到的中心化分片集群相反的,则是去中心化分片集群,典型的例子就是Redis3.x推出的Redis-Cluster集群,这是一种完全意义上的去中心化集群,所有负责读写数据的节点地位平等,并且没有“中心化”的路由节点。

相反,Redis-Cluster中采用了哈希槽的概念,总计16384个槽位,集群初始化时会平均分给每个节点负责管理(支持手动设置),比如现在有四个节点,哈希槽的默认分配如下:

  • A节点:0~4095槽位;
  • B节点:4096~8191槽位;
  • C节点:8192~12287槽位;
  • D节点:12288~16384槽位;

类似于之前0~1516个默认的库一样,每个槽中都可以存放多个Key,同时配备CRC16哈希算法,最终实现数据的分发,例如下述命令:

  • set name zhuzi

则会使用CRC16算法对name这个键名进行哈希,接着取模总槽数16384,从而得出具体要落入的槽位。假设name对应的哈希值是185272,最终落入槽位则是5047(185272%16384-1),即落入到B节点中存储。

既然没有中心化的路由节点,那CRC16+取模运算的工作谁来完成?集群内的所有节点!在Redis-Cluster中,任意节点都具备CRC16取模的能力,来看个场景:

如果一个本该落入A节点的Key,在set时去到了C节点,那么C节点在经过CRC16计算后,会不会把该Key转发到A节点去呢?

答案是不会,而是会向客户端会返回一个重定向错误的消息,其中指示了正确的节点位置,告诉客户端去连接对应节点写入数据即可。

PS:实际项目中,并不会把CRC16+取模的工作交给Redis来做,因为这样有可能会出现一次重定向,通常都是客户端计算,而后直连正确的节点写入数据(如Java中主流的Redis客户端框架,都有实现CRC16的逻辑)。

好了,上述便是去中心化的大体逻辑,相信大家一定明白为啥叫去中心化分片集群,因为不存在中心节点,各个节点自身就具备数据分发计算的能力,即使集群内部分节点宕机,也只会影响部分数据,保证了BASE理论中的基本可用思想,并不会像中心化分片集群那样,一旦中心节点故障,就会造成分片集群不可用。

PS:分库分表领域的Sharding-JDBC,也是一种去中心化分片存储的体现,即各个客户端具备数据分发的能力,不需要依赖MyCat这类中间件实现数据路由。

相较于传统的主从集群,分片式集群的维度显然更高,当应对数据量级、并发规模非常大的系统时,分片式集群能够利用多台机器的共同满足数据需求,它能充分利用集群中每一台机器的资源,实现数据读写的并行处理,以及海量数据的分区存储。也正因如此,早期想实现分片式存储,需要自己研发中间件,反观如今,随着分布式各领域技术的发展,分片式集群成为了新趋势,官方基本都开始支持分片架构。

二、集群篇总结

OK,看到这里,我们一步步阐述了集群中的常用知识,也对集群的形态有了全面认知,但本文并没有涵盖集群的方方面面,实际上,不同类型的集群架构,总会带来各种各样的问题,而这些问题并未做展开,也包括集群与云平台的结合,本文也未曾说明,这些就留给诸位自行去探索啦~

相信看到这里的小伙伴,对集群方面的知识应该建立出了系统化、结构化的认知体系,不过经常阅读我文章的小伙伴会发现,本文中的很多概念,在以往的文章里都有提及,看起来会感觉异常熟悉,为啥?这就是我经常说的那句话:技术学到最后都是共通的,不同技术之间最后都能串起来

不管是业务系统,还是注册中心、定时任务、Redis、MQ、MySQL、ES……等各种组件,在实现集群方案时,底层逻辑都大差不差,本文则是各种技术栈集群方面的共通知识,当你在学不同技术栈的集群技术时,就会发现这些技术之间的共通性。

最后,也希望大家不管在学习什么技术,不要只把目光集中在表层的应用,闲暇之余,记得看看内层的实现思想,这样方能做到一通百通,才能让大家真正成为技术领域的“高手”。

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

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

相关文章

【.Net】DotNetty

文章目录 概述NIO和BIO、AIODotNetty适用场景DotNetty的整体架构和模块DotNetty的使用示例来源 概述 本系列文章主要讲述由微软Azure团队研发的.net的版本的netty,Dotnetty。所有的开发都将基于.net core 3.1版本进行开发。 Dotnetty是什么,原本Netty是…

蓝桥真题--路径之谜DFS解法

路径之谜 思路 前置知识:深度搜索模板搜索所有可以找的路径,将走过的靶子减去一走到最后一个格子的时候,直接去判断所有的靶子只有除最后一个位置的靶子,其余靶子都归零的时候,判断一个最后一个位置横坐标和纵坐标的靶…

PTA C 1050 螺旋矩阵(思路与优化)

本题要求将给定的 N 个正整数按非递增的顺序,填入“螺旋矩阵”。所谓“螺旋矩阵”,是指从左上角第 1 个格子开始,按顺时针螺旋方向填充。要求矩阵的规模为 m 行 n 列,满足条件:mn 等于 N;m≥n;且…

Bayes-RF,基于贝叶斯Bayes优化算法优化随机森林RF分类预测(二分类及多分类皆可)-附代码

Bayesian Optimization(贝叶斯优化)是一种用于超参数调优的技术,对于类似随机森林(Random Forest,简称RF)的机器学习算法非常重要。随机森林是一种集成学习方法,它在训练过程中构建多个决策树&a…

漂亮国的无人餐厅的机器人骚操作

导语 大家好,我是智能仓储物流技术研习社的社长,你的老朋友,老K。行业群 新书《智能物流系统构成与技术实践》 知名企业 读者福利: 👉抄底-仓储机器人-即买即用-免调试 智能制造-话题精读 1、西门子、ABB、汇川&#x…

详解 Redis 在 Centos 系统上的安装

文章目录 详解 Redis 在 Centos 系统上的安装1. 使用 yum 安装 Redis 52. 创建符号链接3. 修改配置文件4. 启动和停止 Redis 详解 Redis 在 Centos 系统上的安装 1. 使用 yum 安装 Redis 5 如果是Centos8,yum 仓库中默认的 redis 版本就是5,直接 yum i…

Premiere Pro 2024:赋予创意翅膀,让你的视频飞翔 mac/win版

Premiere Pro 2024,作为Adobe旗下的旗舰视频编辑软件,自推出以来,一直在视频制作领域占据着重要的地位。随着技术的不断进步和创新,Premiere Pro 2024为用户带来了前所未有的编辑体验,重新定义了视频制作的标准。 Pre…

Unity类银河恶魔城学习记录12-3 p125 Limit Inventory Slots源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释,可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili Inventory.cs using Newtonsoft.Json.Linq; using System.Collections; us…

深入go泛型特性之comparable「附案例」

写作背景 如果你经常遇到一些操作,比如将 map 转换为 slice,判断一个字符串是否出现在 map 中,slice 中是否有重复元素等等,那你对下面这个库肯定不陌生。 github.com/samber/lo最近抽业余时间在看了源码,底层用了范…

云计算的安全需求

目录 一、概述 二、云安全服务基本能力要求 三、信息安全服务(云计算安全类)资质要求 3.1 概述 3.2 资质要求内容 3.2.1 组织与管理要求 3.2.2 技术能力要求 四、云安全主要合规要求 4.1 安全管理机构部门的建立 4.2 安全管理规范计划的编制 4…

【Flutter】Getx设计模式及Provider、Repository、Controller、View等

本文基于Getx 4,x 本本 1、引入 再次接触到Flutter项目,社区俨然很完善和活跃。pubs.dev 寻找状态管理的时候看到很熟悉的Getx时间,俨然发现Getx的版本已到是4.x版本,看到Getx的功能已经非常强大了,庞大的API俨然成为一种开发框架…

Windows Server 2008添加Web服务器(IIS)、WebDAV服务、网络负载均衡

一、Windows Server 2008添加Web服务器(IIS) (1)添加角色,搭建web服务器(IIS) (2)添加网站,关闭默认网页,添加默认文档 在客户端浏览器输入服务器…

蓝桥杯 十一届C++A组 字符排序 21分(运行超时)

思路: 1. 此题考查的冒泡排序中的交换次数,其实就是考察当前数与后面的逆序对个数问题。而为了最大利用位数,应当使每一位都不小于后面的字符,否则会造成一次逆序对的浪费(贪心,为了使总位数最少&#xff…

每日OJ题_优先级队列_堆③_力扣692. 前K个高频单词

目录 力扣692. 前K个高频单词 解析代码 力扣692. 前K个高频单词 692. 前K个高频单词 难度 中等 给定一个单词列表 words 和一个整数 k ,返回前 k 个出现次数最多的单词。 返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率&#xff0c…

《QT实用小工具·三》偏3D风格的异型窗体

1、概述 源码放在文章末尾 可以在窗体中点击鼠标左键进行图片切换,项目提供了一些图片素材,整体风格偏向于3D类型,也可以根据需求自己放置不同的图片。 下面是demo演示: 项目部分代码如下所示: 头文件部分&#xff…

基于SSM+Vue的服装商城系统

绪论 项目研究的背景 困扰管理层的许多问题当中,服装定制将是广大用户们不可忽视的一块。但是管理好服装定制又面临很多麻烦需要解决,例如,如何在工作琐碎,记录繁多的情况下将服装定制的当前情况反应给相关管理人员决策,等等。在此情况下开发一款服装定制系统,于是…

DataLoader的使用

DataLoader的使用 测试DataLoader,batch_size大小为4 import torchvision.datasets from torch.utils.data import DataLoadertest_data torchvision.datasets.CIFAR10("./dataset", trainFalse, transformtorchvision.transforms.ToTensor()) test_loa…

215 基于matlab的快速跟踪算法

基于matlab的快速跟踪算法,提出一种简单又快速、 鲁棒性的算法,基于贝叶斯框架下,该模型 (即图像强度和从目标位置) 的低级功能及周边地区的统计相关性的时空关系。跟踪问题是通过计算信心地图,并将以最大限…

闪站侠洗护管理系统,洗衣洗鞋小程序软件定制,干洗连锁店软件系统搭建;

闪站侠洗护管理系统,洗衣洗鞋小程序软件定制,干洗连锁店软件系统搭建; 为了让每一个洗衣洗鞋工厂与门店的连接更加高效便捷,送洗流程更加简单轻松,拽牛科技倾心打造洗衣洗鞋管理软件。我们的目标是通过高效和优质的服务…

Navicat Premium工具安装教程(超详细讲解)

Navicat Premium是一款功能强大并可支持多连接的数据库管理工具,它允许在单一程序中同时连接多达7种数据库,包括MySQL、MariaDB、MongoDB、SQL server、SQLite、Oracle和PostgreSQl数据库,让管理不同类型的数据库更加快速便捷。 安装Navicat…