接上文,我们创建表t1,列族c1,hbase.root目录为/new。当创建空表时,系统会自动生成一个空region,我们以这个region分配过程看下Region是如何在HMaster和Region server(以下简称rs)中创建的。大致过程如下:
1.HMaster指定分配计划,一个region只会分配给一个rs,多个rs均匀分配
2.多个rs并发执行assiagnment操作
3.先在zk的/hbase/assiangment目录下创建region节点,状态为‘offline’
4.RPC对应rs,请求分配region
5.master端开始等待所有region都被分配,通过zk的节点状态通信
6.rs端收到请求,执行异步OpenRegion操作
7.rs先把zk节点状态改为'opening'
8.rs执行open region操作,并初始化region,主要是创建region的HDFS目录,初始化Store
9.rs修改meta表中region对应的记录信息
10.rs修改zk节点中的状态为'opened'
11.master收到'opened'信息,认为该region已经assiagnment成功
12.所有region都成功后,master认为region批量创建成功
大概类图
在HMaster端提供了BulkAssigner,用来批量分配region,默认采用随即均匀分配,分配过程是一个rpc调用
public boolean bulkAssign(boolean sync) throws InterruptedException, IOException { boolean result = false; ThreadFactoryBuilder builder = new ThreadFactoryBuilder(); builder.setDaemon(true); builder.setNameFormat(getThreadNamePrefix() + "-%1$d"); builder.setUncaughtExceptionHandler(getUncaughtExceptionHandler()); int threadCount = getThreadCount(); java.util.concurrent.ExecutorService pool = Executors.newFixedThreadPool(threadCount, builder.build()); try { //提交任务,任务为SingleServerBulkAssigner populatePool(pool); // How long to wait on empty regions-in-transition. If we timeout, the // RIT monitor should do fixup. //等待 if (sync) result = waitUntilDone(getTimeoutOnRIT()); } finally { // We're done with the pool. It'll exit when its done all in queue. pool.shutdown(); } return result; }
等待过程
boolean waitUntilNoRegionsInTransition(final long timeout, Set<HRegionInfo> regions) throws InterruptedException { // Blocks until there are no regions in transition. //如果带处理的region有一个还在事务列表中,则继续等 //超时时间由hbase.bulk.assignment.waiton.empty.rit设置,默认5分钟 long startTime = System.currentTimeMillis(); long remaining = timeout; boolean stillInTransition = true; synchronized (regionsInTransition) { while (regionsInTransition.size() > 0 && !this.master.isStopped() && remaining > 0 && stillInTransition) { int count = 0; for (RegionState rs : regionsInTransition.values()) { if (regions.contains(rs.getRegion())) { count++; break; } } if (count == 0) { stillInTransition = false; break; } regionsInTransition.wait(remaining); remaining = timeout - (System.currentTimeMillis() - startTime); } } return stillInTransition; }
AssignmentManager提供了assign(final ServerName destination,final List<HRegionInfo> regions)给每个rs批量assign region
void assign(final ServerName destination, final List<HRegionInfo> regions) { .... //强制初始化状态为offline List<RegionState> states = new ArrayList<RegionState>(regions.size()); synchronized (this.regionsInTransition) { for (HRegionInfo region: regions) { states.add(forceRegionStateToOffline(region)); } } ..... // Presumption is that only this thread will be updating the state at this // time; i.e. handlers on backend won't be trying to set it to OPEN, etc. //给每个带分配的region创建zk的节点,目录为/hbase/unassigned,并初始化状态为offline。 //节点创建成功后,在callback中调用zk的exist,设置watcher,在exist操作的callback中将region的状态设为‘PENDING_OPEN’,递增counter //所有region都需要设置成功 AtomicInteger counter = new AtomicInteger(0); CreateUnassignedAsyncCallback cb = new CreateUnassignedAsyncCallback(this.watcher, destination, counter); for (RegionState state: states) { if (!asyncSetOfflineInZooKeeper(state, destination, cb, state)) { return; } } // Wait until all unassigned nodes have been put up and watchers set. int total = regions.size(); for (int oldCounter = 0; true;) { int count = counter.get(); if (oldCounter != count) { LOG.info(destination.toString() + " unassigned znodes=" + count + " of total=" + total); oldCounter = count; } if (count == total) break; Threads.sleep(1); } // Move on to open regions. try { // Send OPEN RPC. If it fails on a IOE or RemoteException, the // TimeoutMonitor will pick up the pieces. //发送RPC请求给rs,如果rpc失败,可重试,最大超时时间60s long maxWaitTime = System.currentTimeMillis() + this.master.getConfiguration(). getLong("hbase.regionserver.rpc.startup.waittime", 60000); while (!this.master.isStopped()) { try { this.serverManager.sendRegionOpen(destination, regions); break; } catch (RemoteException e) { IOException decodedException = e.unwrapRemoteException(); if (decodedException instanceof RegionServerStoppedException) { LOG.warn("The region server was shut down, ", decodedException); // No need to retry, the region server is a goner. return; } else if (decodedException instanceof ServerNotRunningYetException) { // This is the one exception to retry. For all else we should just fail // the startup. long now = System.currentTimeMillis(); if (now > maxWaitTime) throw e; LOG.debug("Server is not yet up; waiting up to " + (maxWaitTime - now) + "ms", e); Thread.sleep(1000); } throw decodedException; } } } ....... }
rs的RPC接口HRegionInterface.openRegions(final List<HRegionInfo> regions),rs初始化region,并通过zk状态告知master是否成功,这是一个异步过程。
用户表open region为OpenRegionHandler,处理
public void process() throws IOException { try { ..... // If fails, just return. Someone stole the region from under us. // Calling transitionZookeeperOfflineToOpening initalizes this.version. //将/hbase/unassigned下的节点状态从‘offline’改成‘opening’ if (!transitionZookeeperOfflineToOpening(encodedName, versionOfOfflineNode)) { LOG.warn("Region was hijacked? It no longer exists, encodedName=" + encodedName); return; } // Open region. After a successful open, failures in subsequent // processing needs to do a close as part of cleanup. //执行open操作 region = openRegion(); if (region == null) { tryTransitionToFailedOpen(regionInfo); return; } boolean failed = true; //open成功后,先更新下zk中的节点时间,再修改meta表中的region记录 //主要是修改meta表中的serverstartcode和server列 if (tickleOpening("post_region_open")) { if (updateMeta(region)) { failed = false; } } //如果修改失败,或者进入stop阶段,关闭region,将zk节点状态设为‘FAILED_OPEN’ if (failed || this.server.isStopped() || this.rsServices.isStopping()) { cleanupFailedOpen(region); tryTransitionToFailedOpen(regionInfo); return; } //将zk节点状态设为‘OPENED’,如果失败,关闭region if (!transitionToOpened(region)) { // If we fail to transition to opened, it's because of one of two cases: // (a) we lost our ZK lease // OR (b) someone else opened the region before us // In either case, we don't need to transition to FAILED_OPEN state. // In case (a), the Master will process us as a dead server. In case // (b) the region is already being handled elsewhere anyway. cleanupFailedOpen(region); return; } // Successful region open, and add it to OnlineRegions //添加到online列表 this.rsServices.addToOnlineRegions(region); ..... }
Region初始化
private long initializeRegionInternals(final CancelableProgressable reporter, MonitoredTask status) throws IOException, UnsupportedEncodingException { ..... // Write HRI to a file in case we need to recover .META. status.setStatus("Writing region info on filesystem"); //写入.regioninfo文件,内容是HRegionInfo序列化的内容,region的元信息 checkRegioninfoOnFilesystem(); // Remove temporary data left over from old regions status.setStatus("Cleaning up temporary data from old regions"); //.tmp目录删除 cleanupTmpDir(); // Load in all the HStores. // // Context: During replay we want to ensure that we do not lose any data. So, we // have to be conservative in how we replay logs. For each store, we calculate // the maxSeqId up to which the store was flushed. And, skip the edits which // is equal to or lower than maxSeqId for each store. //每个family启动一个线程加载store //等全部store都加载后,取最大的seqId和memstoreTS Map<byte[], Long> maxSeqIdInStores = new TreeMap<byte[], Long>( Bytes.BYTES_COMPARATOR); long maxSeqId = -1; // initialized to -1 so that we pick up MemstoreTS from column families long maxMemstoreTS = -1; if (this.htableDescriptor != null && !htableDescriptor.getFamilies().isEmpty()) { // initialize the thread pool for opening stores in parallel. ThreadPoolExecutor storeOpenerThreadPool = getStoreOpenAndCloseThreadPool( "StoreOpenerThread-" + this.regionInfo.getRegionNameAsString()); CompletionService<Store> completionService = new ExecutorCompletionService<Store>(storeOpenerThreadPool); // initialize each store in parallel for (final HColumnDescriptor family : htableDescriptor.getFamilies()) { status.setStatus("Instantiating store for column family " + family); completionService.submit(new Callable<Store>() { public Store call() throws IOException { return instantiateHStore(tableDir, family); } }); } try { for (int i = 0; i < htableDescriptor.getFamilies().size(); i++) { Future<Store> future = completionService.take(); Store store = future.get(); this.stores.put(store.getColumnFamilyName().getBytes(), store); long storeSeqId = store.getMaxSequenceId(); maxSeqIdInStores.put(store.getColumnFamilyName().getBytes(), storeSeqId); if (maxSeqId == -1 || storeSeqId > maxSeqId) { maxSeqId = storeSeqId; } long maxStoreMemstoreTS = store.getMaxMemstoreTS(); if (maxStoreMemstoreTS > maxMemstoreTS) { maxMemstoreTS = maxStoreMemstoreTS; } } ...... } mvcc.initialize(maxMemstoreTS + 1); // Recover any edits if available. maxSeqId = Math.max(maxSeqId, replayRecoveredEditsIfAny( this.regiondir, maxSeqIdInStores, reporter, status)); ....... this.lastFlushTime = EnvironmentEdgeManager.currentTimeMillis(); // Use maximum of log sequenceid or that which was found in stores // (particularly if no recovered edits, seqid will be -1). //递增seqid long nextSeqid = maxSeqId + 1; ...... return nextSeqid; }
rs端的处理就是这些,master端通过zk的watcher监听rs端的region状态修改,AssignmentManager的nodeDataChanged方法就是用来处理这个的。
public void nodeDataChanged(String path) { if(path.startsWith(watcher.assignmentZNode)) { try { Stat stat = new Stat(); //当data变化时,获取data,然后再设置watcher,下次继续处理 RegionTransitionData data = ZKAssign.getDataAndWatch(watcher, path, stat); if (data == null) { return; } handleRegion(data, stat.getVersion()); } catch (KeeperException e) { master.abort("Unexpected ZK exception reading unassigned node data", e); } } }
当rs把region状态设为opening时
case RS_ZK_REGION_OPENING: ..... // Transition to OPENING (or update stamp if already OPENING) //更新时间 regionState.update(RegionState.State.OPENING, data.getStamp(), data.getOrigin()); break;
当rs把region状态设为‘opened‘时
case RS_ZK_REGION_OPENED: ...... // Handle OPENED by removing from transition and deleted zk node //内存状态改为open regionState.update(RegionState.State.OPEN, data.getStamp(), data.getOrigin()); this.executorService.submit( new OpenedRegionHandler(master, this, regionState.getRegion(), data.getOrigin(), expectedVersion)); break;
OpenedRegionHandler主要是删除之前创建的/hbase/unassigned下的region节点
public void process() { // Code to defend against case where we get SPLIT before region open // processing completes; temporary till we make SPLITs go via zk -- 0.92. RegionState regionState = this.assignmentManager.isRegionInTransition(regionInfo); boolean openedNodeDeleted = false; if (regionState != null && regionState.getState().equals(RegionState.State.OPEN)) { openedNodeDeleted = deleteOpenedNode(expectedVersion); if (!openedNodeDeleted) { LOG.error("The znode of region " + regionInfo.getRegionNameAsString() + " could not be deleted."); } } ...... }
节点删除后,又有zk通知,AssignmentManager的nodeDeleted方法
public void nodeDeleted(final String path) { if (path.startsWith(this.watcher.assignmentZNode)) { String regionName = ZKAssign.getRegionName(this.master.getZooKeeper(), path); RegionState rs = this.regionsInTransition.get(regionName); if (rs != null) { HRegionInfo regionInfo = rs.getRegion(); if (rs.isSplit()) { LOG.debug("Ephemeral node deleted, regionserver crashed?, " + "clearing from RIT; rs=" + rs); regionOffline(rs.getRegion()); } else { LOG.debug("The znode of region " + regionInfo.getRegionNameAsString() + " has been deleted."); if (rs.isOpened()) { makeRegionOnline(rs, regionInfo); } } } } }
region上线,将region从transition列表中删除,并更新servers和regions列表
void regionOnline(HRegionInfo regionInfo, ServerName sn) { synchronized (this.regionsInTransition) { RegionState rs = this.regionsInTransition.remove(regionInfo.getEncodedName()); if (rs != null) { this.regionsInTransition.notifyAll(); } } synchronized (this.regions) { // Add check ServerName oldSn = this.regions.get(regionInfo); if (oldSn != null && serverManager.isServerOnline(oldSn)) { LOG.warn("Overwriting " + regionInfo.getEncodedName() + " on old:" + oldSn + " with new:" + sn); // remove region from old server Set<HRegionInfo> hris = servers.get(oldSn); if (hris != null) { hris.remove(regionInfo); } } if (isServerOnline(sn)) { this.regions.put(regionInfo, sn); addToServers(sn, regionInfo); this.regions.notifyAll(); } else { LOG.info("The server is not in online servers, ServerName=" + sn.getServerName() + ", region=" + regionInfo.getEncodedName()); } } // Remove plan if one. clearRegionPlan(regionInfo); // Add the server to serversInUpdatingTimer addToServersInUpdatingTimer(sn); }
小节
region assignment主要关键点
1.region load balance,默认是随即均匀分配
2.master在/hbase/unassigned下建立region节点,方便后续和rs交互
3.rs初始化region在HDFS上的文件目录,包括.regioninfo文件和family目录
4.rs open region之后,将状态设为’opened‘,master认为region assignment成功,删除节点,并将region保存到online列表
相关推荐
HBase的特性与生态:自动分区、LSM Tree、存储...全新的HBase2.0版本新功能:小对象存储MOB、读写链路Off-heap 、Region Replica 、In Memory Compaction 、Assignment MangerV2 、其他;HBase未来规划。 主要章节:
源码中,Master Server的相关模块,如Region Assignment和负载均衡策略,都是优化HBase集群的关键部分。 Zookeeper在HBase中扮演着协调者的角色,用于维护元数据信息和集群状态。通过分析源码中的ZooKeeper相关接口...
uniapp实战商城类app和小程序源码,包含后端API源码和交互完整源码。
本课程是 PHP 进阶系列之 Swoole 入门精讲,系统讲解 Swoole 在 PHP 高性能开发中的应用,涵盖 协程、异步编程、WebSocket、TCP/UDP 通信、任务投递、定时器等核心功能。通过理论解析和实战案例相结合,帮助开发者掌握 Swoole 的基本使用方法及其在高并发场景下的应用。 适用人群: 适合 有一定 PHP 基础的开发者、希望提升后端性能优化能力的工程师,以及 对高并发、异步编程感兴趣的学习者。 能学到什么: 掌握 Swoole 基础——理解 Swoole 的核心概念,如协程、异步编程、事件驱动等。 高并发处理——学习如何使用 Swoole 构建高并发的 Web 服务器、TCP/UDP 服务器。 实战项目经验——通过案例实践,掌握 Swoole 在 WebSocket、消息队列、微服务等场景的应用。 阅读建议: 建议先掌握 PHP 基础,了解 HTTP 服务器和并发处理相关概念。学习过程中,结合 官方文档和实际项目 进行实践,加深理解,逐步提升 Swoole 开发能力。
matlab齿轮-轴-轴承系统含间隙非线性动力学 基于matlab的齿轮-轴-轴承系统的含间隙非线性动力学模型,根据牛顿第二定律,建立齿轮系统啮合的非线性动力学方程,同时也主要应用修正Capone模型的滑动轴承无量纲化雷诺方程,利用这些方程推到公式建模;用MATLAB求解画出位移-速度图像,从而得到系统在不同转速下的混沌特性,分析齿轮-滑动轴承系统的动态特性 程序已调通,可直接运行 ,关键词:Matlab;齿轮-轴-轴承系统;含间隙非线性动力学;牛顿第二定律;动力学方程;修正Capone模型;无量纲化雷诺方程;位移-速度图像;混沌特性;动态特性。,基于Matlab的齿轮-轴-轴承系统非线性动力学建模与混沌特性分析
2024年移动应用隐私安全观测报告.pdf
本电影评论网站管理员和用户。管理员功能有个人中心,用户管理,电影类别管理,电影信息管理,留言板管理,论坛交流,系统管理等。用户可以对电影进行评论。因而具有一定的实用性。本站是一个B/S模式系统,采用SSM框架,MYSQL数据库设计开发,充分保证系统的稳定性。系统具有界面清晰、操作简单,功能齐全的特点,使得电影评论网站管理工作系统化、规范化。 本系统的使用使管理人员从繁重的工作中解脱出来,实现无纸化办公,能够有效的提高电影评论网站管理效率。 关键词:电影评论网站;SSM框架;MYSQL数据库 1系统概述 1 1.1 研究背景 1 1.2研究目的 1 1.3系统设计思想 1 2相关技术 2 2.1 MYSQL数据库 2 2.2 B/S结构 3 2.3 Spring Boot框架简介 4 3系统分析 4 3.1可行性分析 4 3.1.1技术可行性 4 3.1.2经济可行性 5 3.1.3操作可行性 5 3.2系统性能分析 5 3.2.1 系统安全性 5 3.2.2 数据完整性 6 3.3系统界面分析 6 3.4系统流程和逻辑 7 4系统概要设计 8 4.1概述 8 4.2系统结构 9 4.
2023-04-06-项目笔记-第四百三十六阶段-课前小分享_小分享1.坚持提交gitee 小分享2.作业中提交代码 小分享3.写代码注意代码风格 4.3.1变量的使用 4.4变量的作用域与生命周期 4.4.1局部变量的作用域 4.4.2全局变量的作用域 4.4.2.1全局变量的作用域_1 4.4.2.434局变量的作用域_434- 2025-03-13
基于STM32的流量计智能流速流量监测、水泵报警系统(泵启动 1100027-基于STM32的流量计智能流速流量监测、水泵报警系统(泵启动、阈值设置、LCD1602、超阈值报警、proteus) 功能描述: 基于STM32F103C8单片机实现的智能流速、流量,流量计设计 实现的功能是通过信号发生器模拟齿轮传感器,检测流量的大小,同时计算流过液体的总容量 可以设置最大流过的总容量,当超过设定值后通过蜂鸣器与LED灯指示 当没有超过则启动水泵控制电路带动液体流动 1、流速检测 2、流量统计 3、阈值显示与设置(通过按键实现阈值的调节或清零) 4、水泵启动 5、超阈值报警 有哪些资料: 1、仿真工程文件 2、PCB工程文件 3、原理图工程文件 4、源代码 ,核心关键词: 基于STM32的流量计; 智能流速流量监测; 水泵报警系统; 阈值设置; LCD1602; 超阈值报警; Proteus仿真; STM32F103C8单片机; 齿轮传感器; 信号发生器; 流量统计; 蜂鸣器与LED灯指示; 水泵控制电路。,基于STM32的智能流量监测与报警系统(阈值可调、流速与流量监
(灰度场景下的平面、海底、船、受害者)图像分类数据集【已标注,约1100张数据】 数据经过预处理,可以直接作为分类网络输入使用 分类个数【4】:平面、海底、船、受害者【具体查看json文件】 划分了训练集、测试集。存放各自的同一类数据图片。如果想可视化数据集,可以运行资源中的show脚本。 图像分类、分割网络改进:https://blog.csdn.net/qq_44886601/category_12858320.html 计算机视觉完整项目:https://blog.csdn.net/qq_44886601/category_12816068.html
arkime无geo下的oui文件
人脸识别项目实战
人脸识别项目实战
CAD 2025 二次开发dll
人脸识别项目源码实战
c语言学习
基于扩张状态观测器eso扰动补偿和权重因子调节的电流预测控制,相比传统方法,增加了参数鲁棒性 降低电流脉动,和误差 基于扩张状态观测器eso补偿的三矢量模型预测控制 ,基于扩张状态观测器; 扰动补偿; 权重因子调节; 电流预测控制; 参数鲁棒性; 电流脉动降低; 误差降低; 三矢量模型预测控制,基于鲁棒性增强和扰动补偿的电流预测控制方法
c语言学习
UE开发教程与学习方法记录.zip
在智慧园区建设的浪潮中,一个集高效、安全、便捷于一体的综合解决方案正逐步成为现代园区管理的标配。这一方案旨在解决传统园区面临的智能化水平低、信息孤岛、管理手段落后等痛点,通过信息化平台与智能硬件的深度融合,为园区带来前所未有的变革。 首先,智慧园区综合解决方案以提升园区整体智能化水平为核心,打破了信息孤岛现象。通过构建统一的智能运营中心(IOC),采用1+N模式,即一个智能运营中心集成多个应用系统,实现了园区内各系统的互联互通与数据共享。IOC运营中心如同园区的“智慧大脑”,利用大数据可视化技术,将园区安防、机电设备运行、车辆通行、人员流动、能源能耗等关键信息实时呈现在拼接巨屏上,管理者可直观掌握园区运行状态,实现科学决策。这种“万物互联”的能力不仅消除了系统间的壁垒,还大幅提升了管理效率,让园区管理更加精细化、智能化。 更令人兴奋的是,该方案融入了诸多前沿科技,让智慧园区充满了未来感。例如,利用AI视频分析技术,智慧园区实现了对人脸、车辆、行为的智能识别与追踪,不仅极大提升了安防水平,还能为园区提供精准的人流分析、车辆管理等增值服务。同时,无人机巡查、巡逻机器人等智能设备的加入,让园区安全无死角,管理更轻松。特别是巡逻机器人,不仅能进行360度地面全天候巡检,还能自主绕障、充电,甚至具备火灾预警、空气质量检测等环境感知能力,成为了园区管理的得力助手。此外,通过构建高精度数字孪生系统,将园区现实场景与数字世界完美融合,管理者可借助VR/AR技术进行远程巡检、设备维护等操作,仿佛置身于一个虚拟与现实交织的智慧世界。 最值得关注的是,智慧园区综合解决方案还带来了显著的经济与社会效益。通过优化园区管理流程,实现降本增效。例如,智能库存管理、及时响应采购需求等举措,大幅减少了库存积压与浪费;而设备自动化与远程监控则降低了维修与人力成本。同时,借助大数据分析技术,园区可精准把握产业趋势,优化招商策略,提高入驻企业满意度与营收水平。此外,智慧园区的低碳节能设计,通过能源分析与精细化管理,实现了能耗的显著降低,为园区可持续发展奠定了坚实基础。总之,这一综合解决方案不仅让园区管理变得更加智慧、高效,更为入驻企业与员工带来了更加舒适、便捷的工作与生活环境,是未来园区建设的必然趋势。