Hbase 的复制

news2024/10/5 22:58:18

HBase默认采用异步复制的方式同步数据,即客户端执行完put之后,RegionServer的后台线程不断地推送HLog的Entry到Peer集群。这种方式一般能满足大多数场景的需求,例如跨集群数据备份、HBase集群间数据迁移等。但是HBase 1.x版本的复制功能,无法保证Region迁移前后的HLog的Entry按照严格一致的顺序推送到备集群,某些极端情况下可能造成主从集群数据不一致。为此,社区在HBase 2.x版本上实现了串行复制来解决这个问题。
另外,默认的异步复制无法满足强一致性的跨机房热备需求。因为备份机房的数据肯定会落后主集群,一旦主集群异常,无法直接切换到备份集群,因此,社区提出并研发了同步复制。

一、复制场景及原理

1,场景

现在有一个SSD的HBase集群被业务方A访问,业务方A对HBase集群的延迟和可用性要求非常高。现在又收到业务方B的需求,希望对表TableX跑数据分析任务(用MapReduce或者Spark来实现)。对HBase来说,这种任务都是用大量的scan去扫全表来实现的。如果直接去扫SSD在线集群,会极大影响集群的延迟和可用性,对业务方A来说不可接受。另外,业务方B的数据分析任务是一个每天定期跑的任务,希望每次分析的数据都尽可能是最新的数据。
如何解决这个问题?,思路是用一批成本较低的HDD机器搭建一个离线的HBase集群,然后把表TableX的全量数据导入离线集群,再通过复制把增量数据实时地同步到离线集群,业务方B的分析任务直接跑在离线集群上。这样既满足了业务方B的需求,又不会对业务方A造成任何影响。

操作步骤:
(1)先确认表TableX的多个Column Family都已经将REPLICATION_SCOPE设为1。
(2)在SSD集群上添加一条DISABLED复制链路,提前把主集群正在写入的HLog堵在复制队列中。

add_peer '100', CLUSTER_KEY => "zk1,zk2,zk3:11000:/hbase-hdd", STATE => "DISABLED",
               TABLE_CFS => { "TableX" => [] 

(3)对TableX做一个Snapshot,并用HBase内置的ExportSnapshot工具把Snapshot拷贝到离线集群上。注意,不要使用distcp拷贝snapshot,因为容易在某些情况下造成数据丢失。
(4)待Snapshot数据拷贝完成后,从Snapshot中恢复一个TableX表到离线集群。
(5)打开步骤1中添加的Peer:

enable_peer '100'

(6)等待peer=100,所有堵住的HLog都被在线集群推送到离线集群,也就是两个集群的复制延迟等于0,就可以开始在离线集群上跑分析任务了。

注意:为什么需要在步骤2创建一个DISABLED的Peer?
因为步骤3要完成Snapshot到离线集群的拷贝,可能需要花费较长时间。业务方A在此期间会不断写入新数据到TableX,如果不执行步骤2,则会造成离线集群丢失在拷贝Snapshot过程中产生的增量数据,造成主备集群数据不一致。提前创建一个DISABLED的Peer,可以使拷贝Snapshot过程中产生的增量数据都能堆积在Peer的复制队列中,直到拷贝Snapshot完成并enable_peer之后,由在线集群的RegionServer把这一段堵在复制队列中的HLog慢慢推送到离线集群。这样就能保证在线集群和离线集群数据的最终一致性。

2,管理流程的设计和问题

复制功能在HBase 1.x版本上实现的较为粗糙。Peer是指一条从主集群到备份集群的复制链路。一般在创建Peer时,需要指定PeerId、备份集群的ZooKeeper地址、是否开启数据同步,以及需要同步的namespace、table、column family等,甚至还可以指定这个复制链路同步到备份集群的数据带宽。
在HBase 1.x版本中,创建Peer的流程大致如下:HBase客户端在ZooKeeper上创建一个ZNode,创建完成之后客户端返回给用户创建Peer成功。这时HBase的每一个RegionServer会收到创建ZNode的Watch Event,然后在预先注册的CallBack中添加一个名为ReplicationSource,的线程。该Peer在ZooKeeper上维持一个HLog复制队列,写入时产生的新HLog文件名会被添加到这个复制队列中。同时,ReplicationSource不断地从HLog复制队列中取出HLog,然后把HLog的Entry逐个推送到备份集群。
在这里插入图片描述
注意:在HBase 1.x版本的复制功能实现上,存在一些比较明显的问题:
(1)暴露太大的ZooKeeper权限给客户端。HBase客户端必须拥有写ZooKeeper的ZNode的权限,若用户误写ZooKeeper节点,则可能造成灾难性的问题。
(2)创建、删除、修改Peer这些操作都直接请求ZooKeeper实现,不经过RegionServer或者Master服务,HBase服务端无法对请求进行认证,也无法实现Coprocessor。
(3)HBase写了ZNode就返回给客户端。RegionServer添加ReplicationSource线程是异步的,因此客户端无法确认是否所有的RegionServer都成功完成Replication线程创建。若有某一个RegionServer初始化复制线程失败,则会造成该Peer同步阻塞。另外,这种方式也无法实现后续较为复杂的管理流程,如串行复制和同步复制。

3,复制原理

在这里插入图片描述
数据复制的基本流程:
(1)在创建Peer时,每一个RegionServer会创建一个ReplicationSource线程(线程名:replicationSource,10,这里10表示PeerId)。ReplicationSource首先把当前正在写入的HLog都保存在复制队列中。然后在RegionServer上注册一个Listener,用来监听HLog Roll操作。如果RegionServer做了HLog Roll操作,那么ReplicationSource收到这个操作后,会把这个HLog分到对应的walGroup-Queue里面,同时把HLog文件名持久化到ZooKeeper上,这样重启后还可以接着复制未复制完成的HLog。
(2))每个WalGroup-Queue后端有一个ReplicationSourceWALReader的线程,这个线程不断地从Queue中取出一个HLog,然后把HLog中的Entry逐个读取出来,放到一个名为entryBatchQueue的队列内。
(3))entryBatchQueue队列后端有一个名为ReplicationSourceShipper的线程,不断从Queue中取出Log Entry,交给Peer的ReplicationEndpoint。ReplicationEndpoint把这些Entry打包成一个replicateWALEntry操作,通过RPC发送到Peer集群的某个RegionServer上。对应Peer集群的RegionServer把replicateWALEntry解析成若干个Batch操作,并调用batch接口执行。待RPC调用成功之后,ReplicationSourceShipper会更新最近一次成功复制的HLog Position到ZooKeeper,以便RegionServer重启后,下次能找到最新的Position开始复制。

注意问题:
(1)为什么需要把HLog分成多个walGroup-Queue?
一个Peer可能存在多个walGroup-Queue,因为现在RegionServer为了实现更高的吞吐量,容许同时写多个WAL(HBASE-5699),同时写的N个WAL属于N个独立的Group。所以,在一个Peer内,为每一个Group设置一个walGroup-Queue。一种常见的场景是,为每个业务设置一个namespace,然后每个namespace写自己独立的WAL,不同的WAL Group通过不同的复制线程去推,这样如果某个业务复制阻塞了,并不会影响其他的业务(因为不同的namespace产生的HLog会分到不同的walGroup-Queue)。
(2)哪些复制相关的信息是记录在ZooKeeper的?
复制过程中主要有两个重要的信息存放在ZooKeeper上:
1)Peer相关的信息
2)每个RegionServer都在/hbase/replication/rs下有一个独立的目录,用来记录这个Peer下有哪些HLog,以及每个HLog推送到哪个Position。

二、串行复制

1,非串行复制导致的问题

在这里插入图片描述

设想这样一个场景:现在有一个源集群往Peer集群同步数据,其中有一个Region-A落在RegionServer0(简称RS0)上。此时,所有对Region-A的写入,都会被记录在RegionServer0对应的HLog-0内。但是,一旦Region-A从RegionServer0移到RegionServer1上,之后所有对Region-A的写入,都会被RegionServer1记录在对应的HLog-1内。这时,就至少存在两个HLog同时拥有Region-A的写入数据了,而RegionServer0和RegionServer1都会为Peer开一个复制线程(ReplicationSource)。也就是说,RegionServer0和RegionServer1会并行地把HLog-0和HLog-1内包含Region-A的数据写入Peer集群。

不同的RegionServer并行地把同一个Region的数据往Peer集群推送,主要注意的问题:

第一个问题:
写入操作在源集群的执行顺序和Peer集群的执行顺序不一致。
在这里插入图片描述
Region-A在源集群的写入顺序为:
1)t1时间点执行:Put,K0,V0,t1。
2)t2时间点执行:Put,K0,V0,t2。
3)在t3时间点,Region-A从RegionServer0移到RegionServer1上。
4)t4时间点执行:Put,K0,V0,t5。
由于RegionServer可能并行地把同一个Region的数据往Peer推送,那么数据到了Peer集群的写入顺序可能变成:
1)t6时间点执行:Put,K0,V0,t1。
2)t7时间点执行:Put,K0,V0,t5。
3)t8时间点执行:Put,K0,V0,t2。
可以看到,时间戳为t5的Put操作反而在时间戳为t2的Put操作之前写入到Peer集群。那么,在Peer集群的[t7,t8)时间区间内,用户可以读取到t1和t5这两个版本的Put,但这种状态在源集群是永远读取不到的。
对于那些依赖HBase复制功能的消息系统来说,这意味着消息的发送顺序可能在复制过程中被颠倒。对那些要求消息顺序严格一致的业务来说,发生这种情况是不可接受的。

第二个问题:
在极端情况下,可能导致主集群数据和备集群数据不一致。
在这里插入图片描述
由于写入操作在Peer集群执行可能乱序,左侧源集群的写入顺序到了Peer集群之后,就可能变成如右侧所示写入顺序。如果Peer集群在t7和t9之间,执行了完整的Major Compaction,那么执行Major Compaction之后,K0这一行数据全部都被清理,然后在t9这个时间点,时间戳为t2的Put开始在Peer集群执行。
这样最终导致的结果就是:源集群上rowkey=K0的所有cell都被清除,但是到了Peer集群,用户还能读取到一个多余的Put(时间戳为t2)。在这种极端情况下,就造成主备之间最终数据的不一致。对于要求主备集群最终一致性的业务来说,同样不可接受。

2,串行复制的设计思路

为了解决非串行复制的问题,先思考一下产生该问题的原因。根本原因在于,Region从一个RegionServer移动到另外一个RegionServer的过程中,Region的数据会分散在两个RegionServer的HLog上,而两个RegionServer完全独立地推送各自的HLog,从而导致同一个Region的数据并行写入Peer集群。

解决思路就是:把Region的数据按照Region移动发生的时间点t0分成两段,小于t0时间点的数据都在RegionServer0的HLog上,大于t0时间点的数据都在RegionServer1的HLog上。让RegionServer0先推小于t0的数据,等RegionServer0把小于t0的数据全部推送到Peer集群之后,RegionServer1再开始推送大于t0的数据。这样,就能保证Peer集群该Region的数据写入顺序完全和源集群的顺序一致,从而解决非串行复制带来的问题。

从整个时间轴上来看,Region可能会移动N次,因此需要N个类似t0这样的时间点,把时间轴分成N+1个区间。只要依次保证第i(0≤i<N)个区间的数据推送到Peer集群之后,再开始推送第i+1个区间的数据,那么非串行复制的问题就能解决。

HBase社区版本的实现有三个重要的概念:
(1)Barrier:和上述思路中t0的概念类似。具体指的是,每一次Region重新Assign到新的RegionServer时,新RegionServer打开Region前能读到的最大SequenceId(对应此Region在HLog中的最近一次写入数据分配的Sequence Id)。因此,每Open一次Region,就会产生一个新的Barrier。Region在Open N次之后,就会有N个Barrier把该Region的SequenceId数轴划分成N+1个区间。
(2)LastPushedSequenceId:表示该Region最近一次成功推送到Peer集群的HLog的SequenceId。事实上,每次成功推送一个Entry到Peer集群之后,都需要将LastPushedSequenceId更新到最新的值。
(3)PendingSequenceId:表示该Region当前读到的HLog的SequenceId。
在这里插入图片描述
HBase集群只要对每个Region都维护一个Barrier列表和LastPushedSequenceId,就能按照规则确保在上一个区间的数据完全推送之后,再推送下一个区间的数据。以图10-7所示的情况为例,LastPushedSeqenceId在Range-2区间内,说明Range-2这个区间有一个RegionServer正在推送该Region的数据,但是还没有完全推送结束。那么,负责推送Range-3区间的RegionServer发现上一个区间的HLog还没有完全推送结束,就会休眠一段时间之后再检查一次上一个区间是否推送结束,若推送结束则开始推本区间的数据;否则继续休眠。
串行复制功能由小米HBase研发团队设计并提交到社区,目前已经整合到HBase 2.x分支。对此功能有需求的读者,可以尝试使用此功能。

三、同步复制

通常,我们所说的HBase复制指的是异步复制,即HBase客户端写入数据到主集群之后就返回了,然后主集群再异步地把数据依次推送到备份集群。这样存在的一个问题是,若主集群因意外或者Bug无法提供服务时,备份集群的数据是比主集群少的。这时,HBase的可用性将受到极大影响,如果把业务切换到备份集群,则必须接受备份集群比主集群少的这个事实。
事实上,有些在线服务业务对可用性和数据一致性要求极高,这些业务期望能为在线集群搭建备份集群,一旦主集群可用性发生抖动,甚至无法提供服务时,就马上切换到备份集群上去,同时还要求备份集群的数据和主集群数据保持一致。这种需求是异步复制没法保证的,而HBase 2.1版本上实现的同步复制可以满足这类需求。

1,设计思路

在这里插入图片描述
同步复制的核心思想是,RegionServer在收到写入请求之后,不仅会在主集群上写一份HLog日志,还会同时在备份集群上写一份RemoteWAL日志,如图10-8所示。只有等主集群上的HLog和备集群上的RemoteWAL都写入成功且MemStore写入成功后,才会返回给客户端,表明本次写入请求成功。除此之外,主集群到备集群之间还会开启异步复制链路,若主集群上的某个HLog通过异步复制完全推送到备份集群,那么这个HLog在备集群上对应的RemoteWAL则被清理,否则不可清理。因此,可以认为,RemoteWAL是指那些已经成功写入主集群但尚未被异步复制成功推送到备份集群的数据。
对主集群的每一次写入,备份集群都不会丢失这次写入数据。一旦主集群发生故障,只需要回放RemoteWAL日志到备集群,备集群马上就可以为线上业务提供服务。这就是同步复制的核心设计。

2,集群复制的几种状态

为了方便实现同步复制,我们将主集群和备集群的同步复制状态分成4种
(1)Active(简称A):这种状态的集群将在远程集群上写RemoteWAL日志,同时拒绝接收来自其他集群的复制数据。一般情况下,同步复制中的主集群会处于Active状态。
(2)Downgrade Active(简称DA):这种状态的集群将跳过写RemoteWAL流程,同时拒绝接收来自其他集群的复制数据。一般情况下,同步复制中的主集群因备份集群不可用卡住后,会被降级为DA状态,用来满足业务的实时读写。
(3)Standby(简称S):这种状态的集群不容许Peer内的表被客户端读写,它只接收来自其他集群的复制数据。同时确保不会将本集群中Peer内的表数据复制到其他集群上。一般情况下,同步复制中的备份集群会处于Standby状态。
(4)None(简称N):表示没有开启同步复制。

集群的复制状态是可以从其中一种状态切换到另外一种状态的。
在这里插入图片描述

3, 建立同步复制

在这里插入图片描述
建立同步复制过程有三步:
(1)在主集群和备份集群分别建立一个指向对方集群的同步复制Peer。这时,主集群和备份集群的状态默认为DA。
(2)通过transit_peer_sync_replication_state命令将备份集群的状态从DA切换成S。
(3)将主集群状态从DA切换成A。

4,备集群故障处理流程

在这里插入图片描述
当备份集群发生故障时,处理流程:
(1)先将主集群状态从A切换为DA。因为此时备份集群已经不可用,那么所有写入到主集群的请求可能因为写RemoteWAL失败而失败。我们必须先把主集群状态从A切成DA,这样就不需要写RemoteWAL了,从而保证业务能正常读写HBase集群。后续业务的写入已经不是同步写入到备份集群了,而是通过异步复制写入备份集群。
(2)在确保备份集群恢复后,可以直接把备份集群状态切换成S。在第1步到第2步之间的数据都会由异步复制同步到备份集群,第2步后的写入都是同步写入到备份集群,因此主备集群数据最终是一致的。
(3)最后把主集群状态从DA切换成A。

5,主集群故障处理流程

在这里插入图片描述
当主集群发生故障时,处理流程:
(1)先将备份集群状态从S切换成DA,切换成DA之后备份集群将不再接收来自主集群复制过来的数据,此时将以备份集群的数据为准。注意,S状态切换成DA状态的过程中,备集群会先回放RemoteWAL日志,保证主备集群数据一致性后,再让业务方把读写流量都切换到备份集群。
(2)t4时间点,主集群已经恢复,虽然业务已经切换到原来的备集群上,但是原来的主集群还认为自己是A状态。
(3)t5时间点,在上面“建立同步复制”中提到,备份集群建立了一个向主集群复制的Peer,由于A状态下会拒绝所有来自其他集群的复制请求,因此这个Peer会阻塞客户端写向备集群的HLog。这时,我们直接把原来的主集群切换成S状态,等原来备集群的Peer把数据都同步到主集群之后,两个集群的数据将最终保持一致。
(4)t6时间点,把备集群状态从DA切换成A,继续开启同步复制保持数据一致性。

四、同步复制和异步复制对比

1,读路径

异步复制:无影响
同步复制:无影响

2,写路径

异步复制:无影响
同步复制:需要写一份Remote WAL

3,网络带宽

异步复制:需要占用集群的1倍带宽。
同步复制:需要占用2倍宽带,其中1倍来自实现异步复制,另外1倍实现Remote WAL。

4,存储空间

异步复制:无需占用额外的存储空间。
同步复制:Remote WAL会占用1倍WAL存储空间

5,最终一致性

异步复制:若主集群无法恢复,则无法保 证数据的最终一致性。
同步复制:总能保证数据的最终一致性

6,可用性

异步复制:若主集群故障,则业务不可用。
同步复制:若主集群故障,只需要很少时间回放Remote WAL便可提供服务,可用性更高。

7,运维复杂性

异步复制:运维操作简单。
同步复制:操作较为复杂,需要在理解当前集群的状态的情况下手动(或独立的服务)切换主备集群。

8,写入性能对比

针对同步复制和异步复制的写场景,社区用YCSB做了一次压力测试。目前HBase 2.1版本,同步复制的写入性能比异步复制的写入性能下降13%左右(HBASE-20751)。后续,社区会持续对同步复制的写入性能进行优化,为对同步复制有需求的用户提供更好的性能体验。

文章来源:《HBase原理与实践》 作者:胡争;范欣欣

文章内容仅供学习交流,如有侵犯,联系删除哦!

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

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

相关文章

【群晖Drive私有云】利用cpolar内网穿透实现公网远程群晖Drive

文章目录前言1.群晖Synology Drive套件的安装1.1安装Synology Drive套件1.2 设置Synology Drive套件1.3 局域网内电脑测试和使用2.使用cpolar远程访问内网Synology Drive2.1 Cpolar云端设置2.2 Cpolar本地设置2.3 测试和使用3. 结语前言 群晖作为专业的数据存储中心&#xff0…

路径规划 | 图解动态A*(D*)算法(附ROS C++/Python/Matlab仿真)

目录0 专栏介绍1 什么是D*算法&#xff1f;2 D*算法核心概念一览3 D*算法流程图4 步步图解&#xff1a;算法实例5 算法仿真与实现5.1 ROS C实现5.2 Python实现0 专栏介绍 &#x1f525;附C/Python/Matlab全套代码&#x1f525;课程设计、毕业设计、创新竞赛必备&#xff01;详…

【工具】logseq 使用分享

Github: https://github.com/logseq/logseq 三月八日国际劳动妇女节&#xff0c;当然要分享一款好用的记事本软件。 这次介绍的笔记本软件叫 logseq。 logseq 与传统的笔记软件不同&#xff0c;传统的笔记软件有各种数据单元&#xff08;post、title、refs、category、tags、…

智慧灌区信息化解决方案

系统概述智慧灌区信息化解决方案主要对对灌区的水情、雨情、土壤墒情、气象等信息进行监测&#xff0c;对重点区域进行视频监控&#xff0c;同时对泵站、闸门进行远程控制&#xff0c;实现了信息的测量、统计、分析、控制、调度等功能。为灌区管理部门科学决策提供了依据&#…

VITA/PYTHON/LUPA families

Image Sensor Group Top to Bottom Portfolio in Industrial Imaging Machine Vision • Factory automation and inspection • Robotic vision • Biometrics High-End Surveillance • Aerial Surveillance • Intelligent Traffic Systems (ITS) • Mapping Medical and Sc…

【UML】软件需求说明书

目录&#x1f981; 故事的开端一. &#x1f981; 引言1.1编写目的1.2背景1.3定义1.4参考资料二. &#x1f981; 任务概述2.1目标2.2用户的特点2.3假定和约束三. &#x1f981; 需求规定3.1 功能性需求3.1.1系统用例图3.1.2用户登录用例3.1.3学员注册用例3.1.4 学员修改个人信息…

Uipath DataTable-FilterDataTable(筛选数据表)

FilterDataTable(筛选数据表) 活动描述 FilterDataTable(筛选数据表)&#xff1a;通过在“筛选器向导”窗口中指定条件来筛选“DataTable”数据表变量&#xff0c;可以根据在该向导中指定的逻辑条件保留或删除行或列。使用如下图&#xff1a; FilterDataTable(筛选数据表)属…

Graph Partition: Edge cut and Vertex cut

Graph PartitionEdge cut and Vertex cutEdge cutVertex cut实际如何进行点分割和边分割的呢&#xff1f;Graph store format情况1&#xff1a;按照边列表存储&#xff1a;情况2&#xff1a;按照邻接表存储&#xff1a;Edge cut and Vertex cut 图结构描述了数据流动&#xff…

项目经理必看!常用的项目管理工具及方法

本文为你介绍&#xff1a;1、好用的项目管理工具&#xff1b;2、项目管理方法 随着企业日益复杂的业务流程和庞大的项目数量&#xff0c;如何高效地管理项目成为了必须面对的挑战&#xff0c;许多企业开始使用项目管理工具和方法来更好地管理项目。 今天我就来介绍几个好用的…

【UE】大世界子关卡StreamingLevel加载流程

受限于硬件&#xff0c;当项目需要制作大世界的时候&#xff0c;整张大地图无法也没必要全部加载进内存。和所有支持大世界的引擎一样&#xff0c;UE采取了分块加载的方式&#xff1a;除了一个持久关卡&#xff08;PersistentLevel&#xff09;的加载以外&#xff0c;采用的都是…

网络通信快速入门

&#x1f3e1;个人主页 &#xff1a; 守夜人st &#x1f680;系列专栏&#xff1a;Java …持续更新中敬请关注… &#x1f649;博主简介&#xff1a;软件工程专业&#xff0c;在校学生&#xff0c;写博客是为了总结回顾一些所学知识点 目录网络编程实现网络编程的三要素&#x…

少儿编程 电子学会图形化编程等级考试Scratch一级真题解析(选择题)2022年12月

少儿编程 电子学会图形化编程等级考试Scratch一级真题解析2022年12月 选择题(共25题,每题2分,共50分) 1、小明想在开始表演之前向大家问好并做自我介绍,应运行下列哪个程序 A、 B、 C、 D、 答案:D

【MySQL】第17章_触发器

第17章_触发器 在实际开发中&#xff0c;我们经常会遇到这样的情况&#xff1a;有 2 个或者多个相互关联的表&#xff0c;如商品信息和库存信息分别存放在 2 个不同的数据表中&#xff0c;我们在添加一条新商品记录的时候&#xff0c;为了保证数据的完整性&#xff0c;必须同时…

Linux - 内存性能评估

文章目录概述free 命令指定的时间段内不间断地监控内存的使用情况通过watch与free相结合动态监控内存状况vmstat命令监控内存“sar –r”命令组合小结概述 内存的管理和优化是系统性能优化的一个重要部分&#xff0c;内存资源的充足与否直接影响应用系统的使用性能。在进行内存…

C语言-基础了解-07-C运算符

c运算符 一、算术运算符 假设变量 A 的值为 10&#xff0c;变量 B 的值为 20&#xff0c;则&#xff1a; 实例 #include <stdio.h>int main() {int a 21;int b 10;int c ;c a b;printf("Line 1 - c 的值是 %d\n", c );c a - b;printf("Line 2 - …

机器学习100天(四十一):041 对偶支持向量机-公式推导

《机器学习100天》完整目录:目录 机器学习 100 天,今天讲的是:对偶支持向量机-公式推导! 本节主要延续上一节的内容,推导线性支持向量机的对偶形式。本节内容包含的数学理论和推导很多,我尽量简化其中的数学部分,只做感性的介绍,便于大家在理解的同时不受数学复杂公式…

ubuntu 18.04 虚拟机分区扩容

我的虚拟机存在一个问题&#xff0c;原来分配的是60G的空间&#xff0c;但实际只用了30G就已经最显示空间已经满&#xff0c;没办法使用:通过fdisk -l查看分区情况查看LVM卷组的信息Free PE / Size 7551 / <29..50 GiB&#xff0c;这是还可以扩充的大小#lvextend -L 10G /de…

git常用命令汇总

Git 是一种分布式版本控制系统&#xff0c;它具有以下优点&#xff1a; 分布式&#xff1a;每个开发者都可以拥有自己的本地代码仓库&#xff0c;不需要连接到中央服务器&#xff0c;这样可以避免单点故障和网络延迟等问题。 非线性开发&#xff1a;Git 可以支持多个分支并行开…

踩坑:解决npm版本升级报错,无法安装node-sass的问题

npm版本由于经常更新&#xff0c;迁移前端项目时经常发现报错安装不上。 比如&#xff0c;项目经常使用的sass模块&#xff0c;可能迁移的时候就发现安装不了。 因为node-sass 编译器是通过 C 实现的。在 Node.js 中&#xff0c;采用 gyp 构建工具进行构建 C 代码&#xff0c…

自制有声书阅读器:用PaddleSpeech打开读书新方式

吕声辉&#xff0c;飞桨开发者技术专家&#xff08;PPDE&#xff09;&#xff0c;某网络科技公司研发工程师。主要研究方向为图像识别&#xff0c;自然语言处理等。 • AI Studio主页 https://aistudio.baidu.com/aistudio/personalcenter/thirdview/227158 项目背景 随着互联…