第四届字节跳动青训营讲师非常用心给大家整理了课前、中、后的学习内容,同学们自我评估,选择性查漏补缺,便于大家更好的跟上讲师们的节奏,祝大家学习愉快,多多提问交流~
第一节:深入浅出 HBase 实战
概述
本节课程主要分为四个方面:
- 介绍 HBase 的适用场景和数据模型
- 分析 HBase 的整体架构和模块设计
- 针对大数据场景 HBase 的解决方案
- 分享 HBase 大规模实战的最佳实践
课前 (必须)
分布式系统理论基础
HBase 核心数据模型
- HBase 是存储计算分离架构,以 HDFS 作为分布式存储底座。数据实际存储在 HDFS。
- HBase 依赖 Zookeeper 实现元数据管理和服务发现。Client 通过 Zookeeper 配置连接到 HBase集群
- Log-Structured Merge Tree 了解 LSM tree 的基本结构和特性。
-
HBase 写流程:
- 数据先写入 WAL 持久化,用于宕机时恢复内存里丢失的数据;
- 再写入内存态 MemStore,以一种跳表(SkipList)数据结构提供有序的数据和高效的随机读写;
- 当满足特定条件时(比如内存中数据过多,或间隔时间过长),MemStore 数据以 HFile 格式写入 HDFS
-
HBase 读流程
- 首次读某个 rowkey 时,client 需要从 Zookeeper 获取 hbase:meta 表位于哪个 RegionServer上;
- 然后访问该 RegionServer 查询 hbase:meta 表该 rowkey 对应 region 所在的 RegionServer B;
- Client 缓存该位置信息,去 RegionServer B 读取 rowkey;
- 基于该region内可能存在该 rowkey 的 HFile 和 MemStore 构建一个最小堆,用以全局有序地 scan 数据(具体实现可搜索参考 LSM tree 设计原理)
-
Compaction
-
HBase 基于策略和定期整理 HFile 文件集合,将多个有序小文件合并成若干个有序的大文件。
-
HBase 提供两种 compaction 类型:
- Minor compaction: 指选取一些小的、相邻的StoreFile将他们合并成一个更大的StoreFile,在这个过程中不会处理已经Deleted或Expired的Cell。一次 Minor Compaction 的结果是更少并且更大的StoreFile。
- Major compaction: 指将所有的StoreFile合并成一个StoreFile,这个过程会清理三类没有意义的数据:被删除的数据、TTL过期数据、版本号超过设定版本号的数据。另外,一般情况下,major compaction时间会持续比较长,整个过程会消耗大量系统资源,对上层业务有比较大的影响。因此线上业务都会将关闭自动触发major compaction功能,改为手动在业务低峰期触发。
-
Compaction 触发条件:
- memstore flush:可以说compaction的根源就在于flush,memstore 达到一定阈值或其他条件时就会触发flush刷写到磁盘生成HFile文件,正是因为HFile文件越来越多才需要compact。HBase每次flush之后,都会判断是否要进行compaction,一旦满足minor compaction或major compaction的条件便会触发执行。
- 后台线程周期性检查: 后台线程 CompactionChecker 会定期检查是否需要执行compaction,检查周期为hbase.server.thread.wakefrequency*hbase.server.compactchecker.interval.multiplier,这里主要考虑的是一段时间内没有写入请求仍然需要做compact检查。其中参数 hbase.server.thread.wakefrequency 默认值 10000 即 10s,是HBase服务端线程唤醒时间间隔,用于log roller、memstore flusher等操作周期性检查;参数 hbase.server.compactchecker.interval.multiplier 默认值1000,是compaction操作周期性检查乘数因子。10 * 1000 s 时间上约等于2hrs, 46mins, 40sec。
- 手动触发:是指通过HBase Shell、Master UI界面或者HBase API等任一种方式 执行 compact、major_compact等命令。
-
客户端定位数据
直连HBase的客户端需要配置对应的Zookeeper信息来定位数据所在的RegionServer,具体包括zookeeper集群实例的地址列表和该hbase集群在zookeeper中对应的根路径。
直连客户端具体定位步骤如下:
- 客户端访问Zookeeper获取元信息表hbase:meta所在的regionserver地址;
- 客户端访问该regionserver查询要读/写的table的rowkey在哪个regionserver;
- 客户端访问存数据的regionserver进行读写。
通过Thrift协议访问HBase的客户端需要ThriftServer的地址,通过ThriftServer转发请求。可以通过Consul实现thriftserver的服务发现。
LSM tree
HBase将每个column family的数据独立管理,称为HStore。一个HStore包含一到多个物理文件块(称为HFile)存储到HDFS。实际存储时每个column family独立存储,一个column family对应多个HFile文件块。
每个HFile内的数据按rowkey有序存储,但HFile间没有顺序保证。这一特点是由于LSM的写入方式决定的,下面介绍LSM树的读写流程:
- 写入:写入操作先记录到Write-Ahead Log持久化(可选)保存,然后写入内存中的MemStore。WAL可以保证实例挂掉或重启后丢失的内存数据可以恢复。
- 读取:从写入逻辑可以看出HFile包含的rowkey范围会有交集,以全局rowkey顺序读取就需要以一种归并排序的形式组织所有HFile。HBase会打开该cf下所有HFile,分别构建一个迭代器用以rowkey从小到大扫对应HFile的数据。所有这些迭代器又以当前指向rowkey的大小组织成一个最小堆,这样堆顶的迭代器指向的rowkey就是下一个全局最小的rowkey。迭代该rowkey后重新调整最小堆即可。
\
课中
适用场景
- “近在线”的海量分布式KV/宽表存储,数据量级达到百TB级以上
- 写密集型应用,高吞吐,可接受一定的时延抖动
- 需要按行顺序扫描的能力
- 接入Hadoop大数据生态
- 结构化、半结构化数据,可以经常新增/更新列属性
- 平滑的水平扩展
\
业务落地场景包括:
- 电商订单数据 抖音电商每日交易订单数据基于 HBase 存储,支持海量数据存储的同时满足稳定低延时的查询需求,并且只需相对很低的存储成本。通过多个列存储订单信息和处理进度,快速查询近期新增/待处理订单列表。同时也可将历史订单数据用于统计、用户行为分析等离线任务。
- 搜索推荐引擎 存储网络爬虫持续不断抓取并处理后的原始网页信息,通过 MapReduce、Flink、Spark 等大数据计算框架分析处理原始数据后产出粗选、精选、排序后的网页索引集,再存储到 HBase 以提供近实时的随机查询能力,为上层的多个字节跳动应用提供通用的搜索和推荐能力。
- 大数据生态 天生融入 Hadoop 大数据生态。对多种大数据组件、框架拥有良好的兼容性,工具链完善,快速打通大数据链路,提高系统构建落地效率,并借助 HDFS 提供可观的成本优势。敏捷平滑的水平扩展能力可以自如地应对数据体量和流量的快速增长。
- 广告数据流 存储广告触达、点击、转化等事件流,为广告分析系统提供快速的随机查询及批量读取能力,助力提升广告效果分析和统计效率。
- 用户交互数据 Facebook 曾使用 HBase 存储用户交互产生的数据,例如聊天、评论、帖子、点赞等数据,并利用 HBase 构建用户内容搜索功能。
- 时序数据引擎 基于 HBase 构建适用于时序数据的存储引擎,例如日志、监控数据存储。例如 OpenTSDB(Open Time Series Database)是一个基于 HBase 的时序存储系统,适用于日志、监控打点数据的存储查询。
- 图存储引擎 基于 HBase 设计图结构的数据模型,如节点、边、属性等概念,作为图存储系统的存储引擎。例如 JanusGraph 可以基于 HBase 存储图数据。
生态
通过在 HBase之上引入各种组件可以使HBase应用场景得到极大扩展,例如监控、车联网、风控、实时推荐、人工智能等场景的需求。
- Phoenix
主要提供SQL的方式来查询HBase里面的数据。一般能够在毫秒级别返回,比较适合OLTP以及操作性分析等场景,支持构建二级索引。
- Spark
很多企业使用HBase存储海量数据,一种常见的需求就是对这些数据进行离线分析,我们可以使用Spark(Spark SQL) 来实现海量数据的离线分析需求。同时,Spark还支持实时流计算,我们可以使用 HBase+Spark Streaming 解决实时广告推荐等需求。
- HGraphDB
分布式图数据库,可以使用其进行图 OLTP查询,同时结合 Spark GraphFrames 可实现图分析需求,帮助金融机构有效识别隐藏在网络中的黑色信息,在团伙欺诈、黑中介识别等。
- GeoMesa
目前基于NoSQL数据库的时空数据引擎中功能最丰富、社区贡献人数最多的开源系统。提供高效时空索引,支持点、线、面等空间要素存储,百亿级数据实现毫秒(ms)级响应;提供轨迹查询、区域分布统计、区域查询、密度分析、聚合、OD 分析等常用的时空分析功能;提供基于Spark SQL、REST、GeoJSON、OGC服务等多种操作方式,方便地理信息互操作。
- OpenTSDB
基于HBase的分布式的,可伸缩的时间序列数据库,适合做监控系统;比如收集大规模集群(包括网络设备、操作系统、应用程序)的监控数据并进行存储,查询。
- Solr
原生的HBase只提供了Rowkey单主键,仅支持对Rowkey进行索引查找。可以使用 Solr来建立二级索引/全文索引来扩展更多查询场景的支持。
功能
Bulkload
大批量向HBase导入数据的功能。使用MapReduce任务直接生成底层存储的HFile文件,并直接移动到HBase存储目录下,节省HBase写路径的开销从而提高写入效率。
Coprocessor
提供一套接口框架,给HBase原生接口添加类似lifecycle hook函数的能力,用来执行用户自定义的功能来扩展HBase的能力,例如二级索引、Observer等功能。
Filter
将用户的过滤逻辑下推到HBase服务端,避免无用数据传输处理开销来提高查询效率。
MOB
Medium Object Storage解决HBase对中等大小对象(10-100MB)的低延迟读写支持,拓宽HBase适用场景。
Snapshot
数据备份功能,将某一时刻的数据以及元数据备份,用于数据恢复、快照读、复制表等功能。
Replication
将一个HBase集群中的数据复制到目标HBase集群,使用WAL将变更记录同步到其他集群。
数据组织方式
HBase是半结构化存储。数据以行(row)组织,每行包括一到多个列簇(column family)。使用列簇前需要通过创建表或更新表操作预先声明column family。
column family是稀疏存储,如果某行数据未使用部分column family则不占用这部分存储空间。
每个column family由一到多个列(column qualifier)组成。column qualifier不需要预先声明,可以使用任意值。
最小数据单元为cell,支持存储多个版本的数据。由rowkey + column family + column qualifier + version指定一个cell。
同一行同一列族的数据物理上连续存储,首先以column qualifier字典序排序,其次以timestamp时间戳倒序排序。
简单起见可以将HBase数据格式理解为如下结构:
// table名格式:"${namespace}:${table}"
// 例如:table = "default:test_table"
[
"rowKey1": { // rowkey定位一行数据
"cf1": { // column family需要预先定义到表结构
"cq_a": { // column qualifier无需定义,使用任意值
"timestamp3": "value3",
// row=rowKey1, column="cf1:cf_a", timestamp=timestamp2
// 定位一个cell
"timestamp2": "value2",
"timestamp1": "value1"
},
"cq_b": {
"timestamp2": "value2",
"timestamp1": "value1"
}
},
"cf3": {
"cq_m": {
"timestamp1": "value1"
},
"cq_n": {
"timestamp1": "value1"
}
},
},
"rowKey3": {
"cf2": { // 缺省column family不占用存储空间
"cq_x": {
"timestamp3": "value3",
"timestamp2": "value2",
"timestamp1": "value1"
},
"cq_y": {
"timestamp1": "value1"
}
},
}
]
主要数据结构
HDFS目录结构
hdfs://base_dir/hbase_cluster_name/data/default/table_name/region_name(e.g.fffe6d7a8e19490f8770fbe8637a686c)/column_family_name/hfile_name(e.g.7a8b82e197274fd7ade1a7f6b20b9417)
MemStore
MemStore数据结构详细介绍可参考 hbasefly.com/2019/10/18/…
MemStore使用SkipList组织KeyValue数据,提供O(logN)的查询/插入/删除操作,支持双向遍历。
具体实现采用JDK标准库的ConcurrentSkipListMap,结构如下图:
写一个KeyValue到MemStore的顺序如下:
- 在JVM堆中为KeyValue对象申请一块内存区域。
- 调用ConcurrentSkipListMap的put(K key, V value)方法将这个KeyValue对象作为参数传入。
HFile
HFile结构介绍详见hbasefly.com/2016/03/25/…
HFile是HBase存储数据的文件组织形式,参考BigTable的SSTable和Hadoop的TFile实现。HFile共经历了三个版本,其中V2在0.92引入,V3在0.98引入。HFileV1版本的在实际使用过程中发现它占用内存多,HFileV2版本针对此进行了优化,HFileV3版本基本和V2版本相同,只是在cell层面添加了Tag数组的支持。这里主要针对V2版本进行分析。
官方文档的HFile结构图如下:
HFlie主要分为4个section
- Scanned block section:顾名思义,表示顺序扫描HFile时所有的数据块将会被读取,包括Leaf Index Block和Bloom Block。
- Non-scanned block section:表示在HFile顺序扫描的时候数据不会被读取,主要包括Meta Block和Intermediate Level Data Index Blocks两部分。
- Load-on-open-section:这部分数据在HBase的region server启动时,需要加载到内存中。包括FileInfo、Bloom filter block、data block index和meta block index。
- Trailer:这部分主要记录了HFile的基本信息、各个部分的偏移值和寻址信息。
\
一个HFile内的数据会被切分成等大小的block,每个block的大小可以在创建表列簇的时候通过参数blocksize => ‘65535’进行指定,默认为64k,大号的Block有利于顺序Scan,小号Block利于随机查询,需要根据使用场景来权衡block大小。
HFileBlock
block有多种类型,除了data block还包括index block和bloom block来优化数据读取。但格式统一抽象如下:
Data Block
HBase中数据存储的最小文件单元。主要存储用户的KeyValue数据。KeyValue是HBase数据表示的最基础单位,每个数据都是以KeyValue结构在HBase中进行存储。KeyValue结构的内存/磁盘表示如下:
可以看出Row、ColumnFamily、ColumnQualifier是每个KeyValue都会存储,有明显的信息冗余。因此设计名称时最好比较精简,尽量减小重复信息占用的存储。
Block Index
索引分为单层和多层两种。单层即root data index,在打开HFile时就全量加载进内存。结构表示如下:
- Block Offset 表示索引指向数据块的偏移量,
- BlockDataSize 表示索引指向数据块在磁盘上的大小,
- BlockKey 表示索引指向数据块中的第一个key
- 其他三个字段记录HFile所有Data Block中最中间的一个Data Block,用于在对HFile进行split操作时,快速定位HFile的中间位置
Root Index Entry不是定长的,因此需要在Trail Block中的dataIndexCount记录entry数量才能保证正常加载。
NonRoot Index一般有intermediate和leaf两层,具有相同结构。Index Entry指向leaf索引块或者数据块。NonRoot index通过entry Offset实现索引块内的二分查找来优化查询效率。
完整的索引流程如下图,rowkey通过多级索引以类似B+树的方式定位到所属的数据块。
HBase集群架构
Zookeeper
提供分布式一致性的元数据管理服务。HBase使用Zookeeper实现master节点信息登记、master节点选主、RegionServer信息登记、分布式任务管理等功能。
HMaster
元信息管理组件,以及集群调度、保活等功能。通常部署一个主节点和一到多个备节点,通过Zookeeper选主。
RegionServer
提供数据读写服务,每个实例负责一段不重叠的连续rowkey范围内的数据。
ThriftServer
提供一层以Thrift协议访问数据的代理层。
HMaster主要组件
CatalogJanitor
定期扫描元数据hbase:meta的变化,回收无用的region(仅当没有region-in-transition时)。
scan方法执行扫描、回收操作:
- 扫描一遍hbase:meta找出可回收的region,检查元数据一致性并生成报告实例
- 已完成merge或split的region都可被回收,即子目录/父目录没有reference文件后
-
创建GCMultipleMergedRegionsProcedure/GCRegionProcedure异步回收regions
-
GCMultipleMergedRegionsProcedure步骤:
- merge的两个源region分别创建GCRegionProcedure删除region数据
- 删除merge生成region元信息的merge qualifiers(info:mergeN)
-
GCRegionProcedure步骤:
- archive要回收region的HFiles
- 删除region对应的WAL
-
assignmentManager删除region state
-
meta表删除该region记录
-
masterService、FavoredNodesManager删除该region
-
AssignmentManager
管理region分配,processAssignQueue方法每当pendingAssignQueue放满RegionStateNode时批量处理。单独启动daemon线程循环处理。
processAssignmentPlans方法雇用LoadBalancer
- 首先尝试尽量保持现有分配
- 将分配plan的目标server region location更新到对应RegionStateNode中
- 将regionNNode的ProcedureEvent放入队列,统一唤醒所有regionNodes的events上等待的procedures
- 不保持原有分配的通过loadbalancer的round-robin策略分配(原则是不能降低availability)
- 分配失败的塞回pendingAssignQueue下次重新处理
setupRIT方法处理RIT,仅仅是设置RegionStateNode的this.procedure和ritMap
HMaster启动流程
- 先将自己加到backup master的ZK目录下,这样抢主失败了active master能感知到backup;
- 除非关闭master,无限循环尝试写入active master的ZK目录来抢主,成功的话从backup目录删除自己的znode;失败的话监听ZK上activeMaster的znode,主挂了就再次抢主
-
初始化文件系统相关组件
- MasterFileSystem - 封装对底层HDFS文件系统的交互
- MasterWalManager - 封装master分裂WAL操作,管理WAL文件、目录
- TableDescriptor - 管理table信息,预加载所有table的信息
- 发布clusterID到ZK,位于/hbase/hbaseid
- 加文件锁防止hbck1在hbase2集群执行造成数据损坏
-
初始化以下master状态管理组件
-
ServerManager - 管理regionserver状态(online/dead),处理rs启动、关闭、恢复
-
SplitWALManager - 代替ZK管理split WAL的procedures,
-
ProcedureExecutor - 负责调度、执行、恢复procedures,包含以下组件
- WALProcedureStore - 持久化记录procedure状态,用于故障恢复未完成的procedure。
- MasterProcedureScheduler - 针对procedure类型选择合适的并发控制,例如region是server/namespace/table/region等粒度,大致原理是提供不同等级的queue来跑任务。
- 只init procedureExecutor来加载procedures但不开始让workers执行,因为要等DeadServers的ServerCrashProcedures调度执行完成,避免重复执行SCP。
-
AssignmentManager - 负责调度region,包含以下组件
- RegionStates - 管理内存态的region状态,包括online/offline/RIT的region信息 RegionStateNode表示一个region的内存态状态,和meta表保持一致,会关联TransitRegionStateProcedure以保证最多一个RIT在并发
- RegionStateStore - 负责更新region state到meta表 AssignmentManager::start()方法从ZK路径
meta-region-server加载meta region state,对第一个meta region(hbase:meta,,1.1588230740)上锁后设置region location、state、唤醒等待着meta region online的event - 从procedure列表里找出RIT,即未完成的TransitRegionStateProcedure,由AssignmentManager::setupRIT方法将RIT的procedures绑定到regionStates里对应的region
-
RegionServerTracker - 监听ZK的rs目录管理online servers,对比ServerCrashProcedure列表、HDFS的WAL目录里的alive/splitting rs记录,delta就是dead servers,并分别调用ServerManager::expireServer安排ServerCrashProcedures;将online rs添加到ServerManager管理。ServerCrashProcedure流程如下:
-
SERVER_CRASH_START:如果挂了的rs负责meta表,先进入SERVER_CRASH_SPLIT_META_LOGS状态split meta WAL,将rs状态设为*
SPLITTING_META* , MasterWalManager::splitMetaLog在HDFS找到该rs的WAL目录,移动到-splitting结尾的新路径避免更多WAL写入。 这里支持用ZK或不用ZK两种模式,先介绍用ZK的模式: SplitLogManager::splitLogDistributed方法过滤出该路径下.meta结尾的WAL文件,为每个文件提交一个Task并记录到ZK目录splitWAL下,由ZkSplitLogWorkerCoordination协调online的regionserver认领并通过SplitLogWorker::splitLog方法处理,核心逻辑在WALSplitter::splitLogFile里,依次读取WAL文件每条entry,格式如下:- 对每个WAL entry的region检查lastFlushedSeqID,如果大于WAL entry的seqID就跳过,否则放入buffer,LogRecoveredEditsOutputSink异步批量写到临时目录里对应region的
recovered.edits目录下,具体实现在OutputSink::duRun里,调用LogRecoveredEditsOutputSink::append,最终在ProtobufLogWriter::append方法将rowkey和cells追加写到HDFS里tmp目录下对应region的recovered.edits目录; - 等所有log split都结束后设置serverState为SPLITTING_META_DONE。 不用ZK的模式将上述步骤封装成SplitWALProcedure,由HMaster协调全过程。
- \
-
SERVER_CRASH_ASSIGN_META:ZK模式进入此状态assign meta region上线,然后进入SERVER_CRASH_GET_REGIONS状态获取该宕机rs上的region列表,进入SERVER_CRASH_SPLIT_LOGS状态处理用户数据的WAL split,过程类似上述meta WAL split,全部完成后标记rs的ServerState状态OFFLINE。(非ZK模式通过SplitWALProcedure处理)
-
SERVER_CRASH_ASSIGN状态assign该rs上所有挂掉的region后进入SERVER_CRASH_FINISH状态删除该rs,标记这个dead server处理完成
-
-
TableStateManager - meta表确认已online才能启动,负责更新table state到meta表
-
-
初始化一系列ZK相关的trackers
- LoadBalancer
- RegionNormalizer
- LoadBalancerTracker
- RegionNormalizerTracker
- SplitOrMergeTracker
- ReplicationPeerManager
- DrainingServerTracker
- MetaLocationSyncer + MasterAddressSyncer (client ZK不是observer mode时需要)
- SnapshotManager
- MasterProcedureManagerHost
- InitializationMonitor - zombie master检测 HBASE-21535
- 如果是新建集群,安排InitMetaProcedure来初始化元数据,即创建AssignProcedure把meta表region拉起
-
初始化以下后台服务
- Balancer
- CatalogJanitor
- ExecutorServices
- LogCleaner
- HFileCleaner
- ReplicationBarrierCleaner
- 等待元数据构建完成
- 等待足够多RegionServer加入集群,默认至少1个,可配置数量: hbase.master.wait.on.regionservers.maxtostart hbase.master.wait.on.regionservers.mintostart
- AssignmentManager::joinCluster扫描meta表每行数据,构建regionStates,wake等待meta加载后执行的任务。
-
启动其他Chore服务,如:
- RITChore - 定期巡检RIT数量是否过多并打warn日志和打metrics
- DeadServerMetricRegionChore - 定期打deadServer相关metrics
- TableStateManager::start扫描meta表的
table:statecolumn和HDFS上每个table目录下.tabledesc目录下最新的$seqNum.tableinfo文件(即seqNum最大的.tableinfo文件),将meta表里的tableState添加到内存中的tableState,HDFS里不存在则设置为ENABLED
- assignmentManager::processOfflineRegions对每个offline region创建AssignProcedure,按round-robin策略分配
- 如果开启了favoredNode功能,扫meta创建一个索引多种查询模式(rs->region, region->rs等)的元数据快照来初始化favoredNodesManager
-
启动Chore服务
- ClusterStatusChore
- BalancerChore
- RegionNormalizerChore
- CatalogJanitor
- HbckChore
- assignmentManager检查regionserver实例是否存在不同版本,是则移动所有system table到版本最新的rs上以保证兼容性。
- 初始化quota
- serverManager.clearDeadServersWithSameHostNameAndPortOfOnlineServer清楚deadServer里相同host和port的已经online的rs,因master初始化期间加入的rs未更新状态,见HBASE-5916
- 检查ZK上ACL配置
- 初始化MobCleaner
-
最后刷新下balancer的RegionLocationFinder
-
创建master addr tracker,注册到zk,阻塞等待master上线
- 等待master实例在zk设置集群状态为已上线
- 从zk读取clusterID
- 等待active master上线
- 初始化RegionServerProcedureManagerHost并加载procedures,包括:
RegionServerSnapshotManager
RegionServerFlushTableProcedureManager
- 创建cluster connection和联系master用的rpc client
- 创建RegionServerCoprocessorHost
-
反复尝试向master rpc通知本region server上线,直到成功
-
通过masterAddressTracker.getMasterAddress获取master地址
-
创建rpc通道并调用rpc regionServerStartup。 master实现如下:
- MasterRpcServices.regionServerStartup确认master启动完成
- 调用ServerManager.regionServerStartup检查clock ske,以及发起请求的region server是否被记录为dead,是则返回异常让rs自杀。(每次rs启动会携带递增的start code以唯一标识每次重启)通过检查后将该rs加入ServerManager实例内部的onlineServers中(基于ConcurrentSkipListMap)同时移出rsAdmins(HashMap),这里存着未纳入集群的rs。
- response返回master看到的该rs的hostname信息,rs发现不一致的话抛异常
-
- 在zk创建该region server的临时节点并存储infoPort、versionInfo信息
- response还可能返回hbase.rootdir让rs以此目录初始化filesystem。把conf里的rootDir更新成匹配hbase.rootdir配置对应的fs类型,以免用错fs。
- 初始化WAL和replication。在filesystem创建该region server的wal目录。通过反射创建新replication实例
- 启动RegionServerPrecedureManagerHost,启动snapshot handler和其他procesure handlers
- 启动quotaManager
- 定期向master上报负载信息,调用regionServerReport RPC
Master故障恢复
故障恢复流程即从master实例从ZK监听到主master节点掉了,抢主成功后执行上述启动流程。
RegionServer启动流程
先初始化所有组件但不启动,直到reportForDuty成功注册到Hmaster后才启动所有服务。
-
在ctor里初始化(不启动)
-
初始化Netty server event loop用于RPC server/client和WAL
-
检查Memory limit,HFile version,codecs,初始化UserProvider,配置短路读等
-
初始化RSRpcServices,其中是所有RPC接口的实现
-
初始化HFileSystem和FSTableDescriptors
-
初始化ZK,创建:
- ZkCoordinatedStateManager来协调WAL split
- MasterAddressTracker管理ZK上当前active master信息,监听主master变化
- ClusterStatusTracker管理ZK上的cluster配置信息
-
创建ChoreService和ExecutorService
-
拉起rs的webUI
-
-
reportForDuty成功上报HMaster(启动服务)
- 上报前初始化ZK,创建RegionServerProcedureManagerHost并从配置项
hbase.procedure.regionserver.classes加载system procedures、RegionServerSnapshotManager和RegionServerFlushTableProcedureManager - 初始化可以短路优化本地请求的ClusterConnection和用于HMaster通信的client
- 从ZK获取当前active master地址,发送RegionServerStartupRequest向master注册本rs
- 成功收到resp后在handleReportForDutyResponse方法把master返回的KV对加入自身conf,在ZK创建ephemeral znode(默认目录
rs/$hostname,$port,$startcode),把rsInfo写入value,PB格式如下: - 如果resp里有
hbase.rootdir这个key,需要重新初始化FS更新rootDir - ZNodeClearer::writeMyEphemeralNodeOnDisk把rs的ZK ephemeral节点路径写入FS里HBASE_ZNODE_FILE环境变量设置的路径。server正常退出时会删除该文件,用来识别server是否正常退出,加速恢复
- 创建WAL相关目录,并初始化replication的source和sink实例并启动
- 唤醒等待rs online的线程
- 启动snapshotManager和其他procedureHandlers,quotaManager
- 定期调用HMaster的regionServerReport RPC上报server load,报错则尝试重建连接
- 上报前初始化ZK,创建RegionServerProcedureManagerHost并从配置项
RegionServer故障恢复
regionserver每次启动的startcode不同,都视为一个新的rs实例,因此走一遍启动流程。
Region上线流程
Region状态转换统一抽象成TransitRegionStateProcedure。RIT即一个region有未完成的TRSP。常见的状态转换包括以下几种:
-
assign region: GET_ASSIGN_CANDIDATE ------> OPEN -----> CONFIRM_OPENED
-
设置region的candidate rs,AssignmentManager异步用balancer选择rs打开region。assign是封装成一个AssignmentProcedureEvent创建在RegionStateNode里,AssignmentManager::processAssignQueue批量获取待assign region的regionStateNodes,acceptPlan方法里依次调用每个AssignmentProcedureEvent的wakeInternal方法,将阻塞等待在event上的procedures保序加入procedureScheduler调度队列恢复执行。
-
AssignmentManager::regionOpening更新regionNode状态为OPENING,regionStates添加region和对应的rs记录,创建子过程OpenRegionProcedure,这个RemoteProcedure会向目标rs发送executeProcedures RPC,在RSRpcServices::executeOpenRegionProcedures方法里提交AssignRegionHandler异步地通过HRegion.openHRegion做以下操作:
- 写RegionInfo到HDFS上region的目录
/ns/table/encodedRegionName下的.regioninfo文件用于恢复meta表数据。如果相同文件内容已存在就跳过,否则覆盖写(先写到region目录下.tmp目录,再move) - initializeStores并发初始化每个cf的HStore,创建cf的hdfs目录,配置blocksize、hdfs storagePolicy、dataBlockEncoding、cell comparator、TTL、低峰期等,创建memstore,创建StoreEngine(集成storeFlusher,compactionPolicy,Compactor,storeFileManager的工厂实例),遍历HDFS上该region该cf的HFiles创建StoreFileInfo集合,并发打开reader,从HFIie读取元信息compectedFiles并移动到archive目录下WIP here
- 写RegionInfo到HDFS上region的目录
-
- unassign region: CLOSE -----> CONFIRM_CLOSED
- reopen/move region: CLOSE -----> CONFIRM_CLOSED -----> GET_ASSIGN_CANDIDATE ------> OPEN -----> CONFIRM_OPENED
同一时刻一个region只能最多有一个TRSP。
HRegion
Region name格式:
<tablename>,<startKey>,<regionId>_<replicaId>.<encodedName>.
regionId: Usually timestamp from when region was created
encodedName: MD5 hash of the ",,_" part (included only for the new format)
例如:
ycsb_test,user6399,1600830539266_0.3be086687f0a59f0f3fd74d5041be1bd.
MD5哈希值(上例中的3be086687f0a59f0f3fd74d5041be1bd)作为hbase:meta表的rowkey用于查对应region信息。建表时的region pre-split过程就是预先在hbase:meta表写入记录切分好region,比如用"0000"到"9999"之间的多个数值分别作为region start_key。
代码见private void locateInMeta(TableName tableName, LocateRequest req)
Region Split 热点切分
HBase支持的几种常见region split触发策略如下:
- ConstantSizeRegionSplitPolicy:0.94版本前默认切分策略。一个region中最大store的大小大于设置阈值之后触发切分。阈值(hbase.hregion.max.filesize)设置较大对大表比较友好,但是小表就有可能不会触发分裂,极端情况下可能就1;设置较小则对小表友好,但一个大表就会在整个集群产生大量的region。
- IncreasingToUpperBoundRegionSplitPolicy: 0.94版本~2.0版本默认切分策略。总体来看和ConstantSizeRegionSplitPolicy思路相同,一个region中最大store大小大于设置阈值就会触发切分。阈值计算公式 :(#regions) * (#regions) * (#regions) * flush size * 2,最大不超过用户设置的MaxRegionFileSize。这种切分策略很好的弥补了ConstantSizeRegionSplitPolicy的短板,能够自适应大表和小表。
- SteppingSplitPolicy: 2.0版本默认切分策略。如果region个数等于1,切分阈值为flush size * 2,否则为MaxRegionFileSize。这种切分策略对于大集群中的大表、小表会比IncreasingToUpperBoundRegionSplitPolicy更加友好,小表不会再产生大量的小region,而是适可而止。
Region split 步骤如下:
- 找到切分点splitpoint,一般是整个region中最大store中的最大HFile文件中最中心的一个block的首个rowkey。
- HBase将整个切分过程包装成了一个事务,意图能够保证切分事务的原子性。整个分裂事务过程分为三个阶段:prepare – execute – (rollback)
- prepare阶段:在内存中初始化两个子region,具体是生成两个HRegionInfo对象,包含tableName、regionName、startkey、endkey等。同时会生成一个transaction journal,这个对象用来记录切分的进展
- execute阶段:HBase 1.0 版本的 region split 核心操作如下图:
- regionserver 更改ZK节点 /region-in-transition 中该region的状态为SPLITING。
- master通过watch节点/region-in-transition检测到region状态改变,并修改内存中region的状态,在master页面RIT模块就可以看到region执行split的状态信息。
- 在父存储目录下新建临时文件夹.split保存split后的daughter region信息。
- 关闭parent region:parent region关闭数据写入并触发flush操作,将写入region的数据全部持久化到磁盘。此后短时间内客户端落在父region上的请求都会抛出异常NotServingRegionException。
- 核心分裂步骤:在.split文件夹下新建两个子文件夹,称之为daughter A、daughter B,并在文件夹中生成reference文件,分别指向父region中对应文件。生成reference文件的日志如下:
2017-08-12 11:53:38,158 DEBUG [StoreOpener-0155388346c3c919d3f05d7188e885e0-1] regionserver.StoreFileInfo: reference 'hdfs://hdfscluster/hbase-rsgroup/data/default/music/0155388346c3c919d3f05d7188e885e0/cf/d24415c4fb44427b8f698143e5c4d9dc.00bb6239169411e4d0ecb6ddfdbacf66' to region=00bb6239169411e4d0ecb6ddfdbacf66 hfile=d24415c4fb44427b8f698143e5c4d9dc。
reference文件名前半段是父region对应的HFile文件名,后半段是父region的目录名。
reference文件内容包括切分点的rowkey,和一个boolean值表示该子文件夹是上半还是下半部分。
- 父region分裂为两个子region后,将daughter A、daughter B拷贝到HBase根目录下,形成两个新的region。
- parent region通知修改 hbase.meta 表后下线,不再提供服务。下线后parent region在meta表中的信息并不会马上删除,而是标注split列、offline列为true,并记录两个子region。
- 开启daughter A、daughter B两个子region。通知修改 hbase.meta 表,正式对外提供服务。
rollback阶段:如果execute阶段出现异常,则执行rollback操作。为了实现回滚,整个切分过程被分为很多子阶段,回滚程序会根据当前进展到哪个子阶段清理对应的垃圾数据。具体见下图:
Region split过程不会实际移动文件,而是等到下次compaction时处理。在此之前通过子region的reference文件重定向到原来父region的文件去读数据,流程如下:
HBase 2.x 版本的 region split 实现去除了对 Zookeeper 的依赖,通过持久化存储的 Procedure 框架在 HMaster 内部闭环管理切分进度,在 HMaster 故障恢复后可恢复进度继续执行或取消。其他部分的实现和 1.0 版本类似。
Region Merge 碎片整合
region merge可以通过HBaseAdmin手动触发,或由normalization触发。merge流程如下:
- 调用MasterRpcServices::mergeTableRegions方法,从AssignmentManager查找对应regionInfo并调用HMaster::mergeRegions()方法,检查master已完成初始化且merge功能启用后提交NonceProcedureRunnable(关于Nonce的介绍见zhuanlan.zhihu.com/p/75734938)…
- MergeTableRegionsProcedure检查待合并的parent regions是否有重复,是否同table,是否相邻,是否重叠,是否主副本,是否online,集群和table状态是否可以merge。检查通过后排序regions并生成合并后region的RegionInfo(计算合并后的startKey,endKey,regionID取待合并regions最大值+1)
- 调用executeFromState,从MERGE_TABLE_REGIONS_PREPARE状态开始,检查table不能正在打snapshot,merge功能必须开启,如果region上有已merge标记需要成功清除并archive对应HDFS文件。具体逻辑是检查region的目录下是否有referenceFile,没有则提交GCMultipleMergedRegionsProcedure清理已merge的regions文件,并清理HMaster内存里对应的region信息。
GCMultipleMergedRegionsProcedure调用MetaTableAccessor.getMergeRegions检查hbase:meta表里该region的cells,过滤出column为"info:merge.*" regex格式的cell,从value解析RegionInfo,这些就是该region merge前的parent regions。
对父母region分别创建一个GCRegionProcedure,具体在GC_REGION_ARCHIVE状态下调用HFileArchiver.archiveRegion移动region文件到archive目录,如果archive目录下已存在同名文件,尝试加时间戳后缀重命名该文件,失败就删除之。move成功后删除region目录。
然后删除该region对应的WAL文件目录(存着seqid等文件),格式:$rootDir/$cluster/WALs/data/$namespace/table/regionName
然后删除AssignmentManager里该region的状态,再删除meta表里该region的info cf下所有信息。ServerManager::removeRegion清楚该region的两个seqID信息:
- The last flushed sequence id for a store in a region
- The last flushed sequence id for a region
再清理该region的FavoredNodes。
- 从meta表删除子region上对应"info:merge.*" regex格式的cq。至此完成清理父母regions里上次merge留下的元数据。
- 设置AssignmentManager里父母region的状态为MERGING
- 检查quota是否够,跳过正在执行的normalizer
- MERGE_TABLE_REGIONS_CLOSE_REGIONS 关闭父母regions
- MERGE_TABLE_REGIONS_CHECK_CLOSED_REGIONS 检查关闭都完成后
-
MERGE_TABLE_REGIONS_CREATE_MERGED_REGION移除只读副本,创建merge出的新region。具体步骤:
- 在第一个父region目录下创建
.merges临时目录 - 对父母regions的每个cf分别遍历所有storeFiles,每个storeFile分别创建referenceFile,文件名称格式:
${parent_HFile_name_before_merge}.${parent_region_name}文件内容统一指向原文件的startKey,等效于split里指向上半部分的referenceFile内容。 - commitMergedRegion将
.merged临时目录下的内容move到合并后的子region目录下 - AssignmentManager创建新region的状态为MERGING_NEW
- 在第一个父region目录下创建
- MERGE_TABLE_REGIONS_WRITE_MAX_SEQUENCE_ID_FILE:从父母region的seqid里找到最大值,写入子region的seqid文件
- MERGE_TABLE_REGIONS_UPDATE_META:AssignmentManager将子region的状态设为MERGED, 将父母region删除,regionStateStore.mergeRegions方法原子地操作meta表,删除父母region,添加子region。子region的info cf下会写入父母regions的RegionInfo,cq分别是
merge0000和merge0001。子region状态为CLOSED防止过早被master调度拉起。 子region需要添加父母regions作为replication barrier,保证父母regions都完成同步再开始同步子region。
- 创建AssignProcedure打开子region
Merge过程也只是创建reference等compaction才移动数据,移动前读数据方式如下图:
最佳实践
rowkey设计
- 最大长度是64KB,实际应用中长度一般为 10 ~ 100bytes。key在保证功能的前提下建议越短越好,因为key是冗余到每个cell存储的,过长的key会占用更多存储、缓存空间。
- 设计Key时,要充分利用排序存储这个特性,将经常一起读取的行存储到一起。HBase以HFile文件块为单位从HDFS读取数据,一次性读出相邻相关数据可以达到随机读变成顺序读的效果。
但同时要防止出现热key聚焦打爆region server实例。
反例:以时间戳作rowkey前缀,一段时间的请求会全部打到同一regionserver。
Column family数量
过多的cf会影响HBase性能,建议不超过3个。
value大小
建议不要超过1MB。过大的value会影响HBase读写性能。可以将实际value存储在其他对象存储系统,在HBase的value存储其位置信息。
Region数量
一个region的大小最好在10-50GB之间。
mapreduce的应用在低峰期运行
批处理任务建议在业务低峰期运行,并且需要对HBase的访问流量进行一定限制。
尽量复用client实例
新建client实例需要访问Zookeeper和元信息表所在regionserver,频繁操作有打垮服务的风险。
client参数调优
- nodelay设置true
- 读较多的应用中gc的新生代不能设置太小
- 数据版本尽可能少来增加有效缓存容量,提升命中率
- 避免一次scan过多的row,尽量拆分为多次小规模scan作分页查询
课后
- 梳理回顾 HBase 的适用场景,并从架构设计、数据模型等方面解释为什么适用,以及对应场景的 rowkey 应该如何设计?
- 能否完整复述一遍 region split 和 region merge 的过程?
- Distributed log replay 解决了什么问题?是通过什么方式解决的?
- 以时间戳作为 rowkey 前缀会有什么问题?如何解决?
参考资料
- static.googleusercontent.com/media/resea… 介绍 Bigtable,经典的分布式宽表设计,HBase 很多设计借鉴了 Bigtable,可以看作其开源实现版本
- hbase.apache.org/book.html HBase 官方指南,权威全面地介绍 HBase。
- help.aliyun.com/document_de… 阿里云对 HBase 应用场景的整体介绍。
- cloud.tencent.com/developer/a… compaction 机制的简述 Blog。
- opentsdb.net/docs/build/… 介绍 OpenTSDB 在 HBase 上的数据模型设计
- hbasefly.com/category/hb… 详细易懂的 HBase 介绍系列文章,推荐阅读整个系列
- hbasefly.com/2017/08/27/… 介绍较早版本 HBase 依赖ZK的 region 切分的实现细节,来自上述系列文章
- hbasefly.com/2016/03/25/… HFile 具体格式介绍,同样出自上述系列文章
- cloud.tencent.com/developer/a… 详细介绍 HBase competition 和 split 实现
- www.jianshu.com/p/569106a30… 对 HBase 各个功能的快速介绍,可作为索引快速查询相关组件介绍
- www.jianshu.com/p/086c86fb8… 介绍 WAL split 实现的演进过程,以及解决了什么问题
第二节:数据湖三剑客:Delta Lake、Hudi 与 Iceberg 详解
导读
来自36氪
- 数据库行业正走向分水岭。
- 过去几年,全球数据库行业发展迅猛。2020年,Gartner首次把数据库领域的魔力象限重新定义为Cloud DBMS,把云数据库作为唯一的评价方向;2021年,Gartner魔力象限又发生了两个关键的变化:1、Snowflake和Databricks两个云端数据仓库进入领导者象限;2、放开了魔力象限的收入门槛限制,SingleStore、Exasol、MariaDB、Couchbase等数据库新势力首次进入榜单。
- 某种程度上,这种变化的背后,暗示着全球数据库已经进入发展的黄金时代,也是一众新兴势力的加速崛起之年。其中,最为典型的例子是Snowflake和Databricks经常隔空喊话,前者是云端数仓的代表玩家,去年继续保持了1倍以上的业务增长;后者因推出“湖仓一体”,估值一路飙升至360亿美金,两者之争,其实是数据库新旧架构之争。
-
随着企业数字化驶入深水区,对于数据使用场景也呈现多元化的趋势,过去容易被企业忽略的数据,开始从幕后走到台前,如何为众多场景选择一款合适的数据库产品,已经成了很多CIO和管理者的一道必答题。但有一点可以确定的是,过去的数据库已难以匹配眼下日益增长的数据复杂度需求,基于扩展性和可用性划分,分布式架构突破单机、共享、集群架构下的数据库局限,近些年发展态势迅猛。为此,这篇文章我们将主要分析:
- 数据仓、数据湖、湖仓一体究竟是什么?
- 架构演进,为什么说湖仓一体代表了未来?
- 现在是布局湖仓一体的好时机吗?
-
01:数据湖+数据仓≠湖仓一体
- 在湖仓一体出现之前,数据仓库和数据湖是被人们讨论最多的话题。
- 正式切入主题前,先跟大家科普一个概念,即大数据的工作流程是怎样的?这里就要涉及到两个相对陌生的名词:数据的结构化程度和数据的信息密度。前者描述的是数据本身的规范性,后者描述的是单位存储体积内、包含信息量的大小。
- 一般来说,人们获取到的原始数据大多是非结构化的,且信息密度比较低,通过对数据进行清洗、分析、挖掘等操作,可以排除无用数据、找到数据中的关联性,在这个过程中,数据的结构化程度、信息密度也随之提升,最后一步,就是把优化过后的数据加以利用,变成真正的生产资料。
- 简而言之,大数据处理的过程其实是一个提升数据结构化程度和信息密度的过程。在这个过程中,数据的特征一直在发生变化,不同的数据,适合的存储介质也有所不同,所以才有了一度火热的数据仓库和数据湖之争。
- 我们先来聊聊数据仓库,它诞生于1990年,是一个面向主题的、集成的、相对稳定的、反映历史变化的数据集合,主要用于支持管理决策和信息的全局共享。简单点说,数据仓库就像是一个大型图书馆,里面的数据需要按照规范放好,你可以按照类别找到想要的信息。
- 就目前来说,对数据仓库的主流定义是位于多个数据库上的大容量存储库,它的作用在于存储大量的结构化数据,为管理分析和业务决策提供统一的数据支持,虽然存取过程相对比较繁琐,对于数据类型有一定限制,但在那个年代,数据仓库的功能性已经够用了,所以在2011年前后,市场还是数据仓库的天下。
- 到了互联网时代,数据量呈现“井喷式”爆发,数据类型也变得异构化。受数据规模和数据类型的限制,传统数据仓库无法支撑起互联网时代的商业智能,随着Hadoop与对象存储的技术成熟,数据湖的概念应用而生,在2011年由James Dixon提出。
- 相比于数据仓库,数据湖是一种不断演进中、可扩展的大数据存储、处理、分析的基础设施。它就像一个大型仓库,可以存储任何形式(包括结构化和非结构化)和任何格式(包括文本、音频、视频和图像)的原始数据,数据湖通常更大,存储成本也更为廉价。但它的问题也很明显,数据湖缺乏结构性,一旦没有被治理好,就会变成数据沼泽。
- 从产品形态上来说,数据仓库一般是独立标准化产品,数据湖更像是一种架构指导,需要配合着系列周边工具,来实现业务需要。换句话说,数据湖的灵活性,对于前期开发和前期部署是友好的;数据仓库的规范性,对于大数据后期运行和公司长期发展是友好的,那么,有没有那么一种可能,有没有一种新架构,能兼具数据仓库和数据湖的优点呢?
- 于是,湖仓一体诞生了。依据DataBricks公司对Lakehouse 的定义,湖仓一体是一种结合了数据湖和数据仓库优势的新范式,在用于数据湖的低成本存储上,实现与数据仓库中类似的数据结构和数据管理功能。湖仓一体是一种更开放的新型架构,有人把它做了一个比喻,就类似于在湖边搭建了很多小房子,有的负责数据分析,有的运转机器学习,有的来检索音视频等,至于那些数据源流,都可以从数据湖里轻松获取。
- 就湖仓一体发展轨迹来看,早期的湖仓一体,更多是一种处理思想,处理上将数据湖和数据仓库互相打通,现在的湖仓一体,虽然仍处于发展的初期阶段,但它已经不只是一个纯粹的技术概念,而是被赋予了更多与厂商产品层面相关的含义和价值。
-
这里需要注意的是,“湖仓一体”并不等同于“数据湖”+“数据仓”,这是一个极大的误区,现在很多公司经常会同时搭建数仓、数据湖两种存储架构,一个大的数仓拖着多个小的数据湖,这并不意味着这家公司拥有了湖仓一体的能力,湖仓一体绝不等同于数据湖和数据仓简单打通,反而数据在这两种存储中会有极大冗余度。
-
02:为什么说湖仓一体是未来?
- 回归开篇的核心问题:湖仓一体凭什么能代表未来?
- 关于这个问题,我们其实可以换一个问法,即在数据智能时代,湖仓一体会不会成为企业构建大数据栈的必选项?就技术维度和应用趋势来看,这个问题的答案几乎是肯定的,对于高速增长的企业来说,选择湖仓一体架构来替代传统的独立仓和独立湖,已经成为不可逆转的趋势。
- 一个具有说服力的例证是,现阶段,国内外各大云厂商均陆续推出了自己的“湖仓一体”技术方案,比如亚马逊云科技的Redshift Spectrum、微软的Azure Databricks、华为云的Fusion Insight、滴普科技的FastData等,这些玩家有云计算的老牌龙头,也有数据智能领域的新势力。
- 事实上,架构的演进是由业务直接驱动的,如果业务侧提出了更高的性能要求,那么在大数据架构建设的过程中,就需要数据库架构建设上进行技术升级。以国内数字化企业服务领域成长最快的独角兽滴普科技为例,依托新一代湖仓一体、流批一体的数据分析基础平台FastData,基于对先进制造、生物医药、消费流通等行业的深度洞察,滴普科技从实际场景切入,为客户提供了一站式的数字化解决方案。
- 滴普方面认为,“在数据分析领域,湖仓一体是未来。它可以更好地应对AI时代数据分析的需求,在存储形态、计算引擎、数据处理和分析、开放性以及面向AI的演进等方面,要领先于过去的分析型数据库。”以AI应用层面为例,湖仓一体架构天然适合AI类的分析(包括音视频非结构化数据存储,兼容AI计算框架,具有模型开发和机器学习全生命周期的平台化能力),也更适合大规模机器学习时代。
-
这一点,和趋势不谋而合。就在前不久,Gartner发布了湖仓一体的未来应用场景预测:湖仓一体架构需要支持三类实时场景,第一类是实时持续智能;第二类是实时按需智能;第三类是离线按需智能,这三类场景将可以通过快照视图、实时视图以及实时批视图提供给数据消费者,这同样是未来湖仓一体架构需要持续演进的方向。
-
03:现在是布局湖仓一体的好时机吗?
- 从市场发展走向来看,“湖仓一体”架构是基于技术发展进程的必经之路。
- 但由于这个新型开放架构仍处于发展早期,国内外企业数字化水平和市场认知的不同,造成了解决方案也存在着较大的差异。在业内投资人看来,“虽然美国的企业服务市场比我们成熟的多,也有很多路径可以参考,但中国市场却有着很多中国特色。以对标Databricks的滴普科技为例,美国企业服务市场往往卖产品就可以了,但中国大客户群体需要更与客户资深场景深度融合的解决方案,解决方案需要兼顾通用性和定制化。”
- 在此前与滴普科技的合作中,百丽国际就已经完成了统一数仓的搭建,实现了多个业务线的数据采集和各个业务域的数据建设。在保证前端数据正常运行、“热切换”底层应用的前提下,滴普科技和百丽国际紧密协作,在短短几个月时间里将多个数仓整合为统一数仓,有效统一了业务口径,大幅缩减了开发运维工作量,整个业务价值链也形成了闭环。
- 这也是“湖仓一体”的能力价值所在:随着数据结构的逐渐多样性,3D图纸、直播视频、会议视频、音频等数据资料越来越多,为深度挖掘数据价值,依托于领先的湖仓一体技术架构,百丽国际可先将海量的多模数据存储入湖,在未来算力允许时,及挖掘深度的业务分析场景后,从数据湖中抓取数据分析。
- 举个简单的例子,某个设计师想要设计一款鞋子,一般会从历史数据中找有效信息参考,设计师也许只需要一张货品照片,就能像浏览电影般,了解到该商品多年来全生命周期的销售业绩、品牌故事、竞品分析等数据,赋能生产及业务决策,实现数据价值的最大化。
- 一般来说,大体量的企业想要保持持续增长,往往需要依靠大量、有效的数据输出,进而实现智慧决策。很多企业出于 IT 建设能力的限制,导致很多事情没法做,但通过湖仓一体架构,让之前被限制的数据价值得以充分发挥,如果企业能够在注重数据价值的同时,并有意识地把它保存下来,企业就完成了数字化转型的重要命题之一。
- 我们也有理由相信,随着企业数字化转型加速,湖仓一体架构也会有更为广阔的发展空间。
习题
-
阅读Delta Lake开源代码github.com/delta-io/de…
- Delta对于底层存储系统有什么要求
- Delta的Transaction是乐观锁还是悲观锁
- 如下代码实现了什么功能,如何做到的
-
import org.apache.spark.sql.Column; import org.apache.spark.sql.functions; deltaTable.update( new HashMap<String, Column>() {{ put("data", functions.col("data").plus(1)); }} );
-
阅读Delta Lake论文,简述一下其几个use cases
第三节:从 Kafka 到 Pulsar的数据流演进之路
概述
本节课程主要分为四个方面:
- 消息队列概述
- Kafka 详解
- Pulsar 详解
- 周边和生态
课前部分主要罗列课程中涉及到的概念。对于不熟悉的概念,同学们可以提前查询预习;课中部分主要罗列每一部分的关键思路,帮助同学们跟上课程的进度;课后部分是一些问题,帮助同学们在课后梳理本课程的重点。
课前
消息队列的使用场景
- 消息队列在业界主要使用在那些场景
- 消息队列在大数据场景下的用途
常见消息队列
- 常见消息队列,如: Kafka、RocketMQ、Pulsar 架构、高级特性
课中
消息队列概述
-
消息队列应用场景
- MQ 消息通道
- EventBridge 事件总线
- Data Platform 数据流平台
-
主流消息队列介绍
- RabbitMQ
- RocketMQ
- Kafka
- Pulsar
Kafka 详解
- Kafka 架构介绍
- Kafka 高可用
- Kafka 集群扩缩容
- Kafka 未来演进之路
- Kafka 运维/调优经验介绍
Pulsar 详解
- Pulsar 架构介绍
- Bookkeeper 介绍
- Pulsar 特性介绍
- Pulsar 集群 HA & Scale-up
- Pulsar vs Kafka
周边和生态
- 周边生态概览
- Pulsar IO
- Kafka Schema
- Pulsar SQL
课后
- 消息队列的应用场景有哪些?
- Pulsar 相比较与 Kafka 为什么和云原生更加适配?
- 存储计算分离带来的优势?
- 存储计算分离之后,计算层可以做哪些工作?
- Pulsar 在多模存储层可以如何搭配,如S3,HDFS,Bookkeeper等?
- Pulsar 集群扩容 Broker、Bundle、Topic-Partition 之间是如何进行均衡?