邹平建设项目网站公示企业网站托管外包方案
2026/1/15 10:48:17 网站建设 项目流程
邹平建设项目网站公示,企业网站托管外包方案,WordPress主题添加点赞喜欢按钮,南京知名网站建设公司钟看图掌握核心观点#x1f447; 图片 一、背景 在推荐系统中#xff0c;样本拼接是衔接在线服务与算法模型的重要一个环节#xff0c;主要职责是样本拼接和业务相关的ETL处理等#xff0c;模块位置如下图红框所示。 图片 推荐系统通过学习埋点数据来达到个性化精准推荐的…钟看图掌握核心观点图片一、背景在推荐系统中样本拼接是衔接在线服务与算法模型的重要一个环节主要职责是样本拼接和业务相关的ETL处理等模块位置如下图红框所示。图片推荐系统通过学习埋点数据来达到个性化精准推荐的目的因此需要知道服务端推荐下发的内容是否有一系列的行为(曝光点击播放点赞收藏加购等等)把被推荐内容的埋点数据与当下的特征拼接起来的过程一般称为样本拼接一个简化的流程如下图片推荐的过程可以检验概括为以下几点后台服务rank 推荐内容给app客户端同时把内容对应的特征快照保存起来app接收到内容后埋点日志被上报到消息中间件样本拼接负责将特征与埋点日志拼接起来定义正负样本格式转换模型接收样本训练将使用最新的模型做推荐。为了保证较高的拼接率和稳定性我们的拼接架构也经过了长时间的迭代这篇文章我将给大家介绍vivo特征拼接架构的发展历程、当前方案、当前方案遇到的问题和解决方案以及未来的规划和展望希望能帮助到业内的同学。二、拼接方案选型2.1 小时粒度拼接小时拼接是将埋点日志和特征快照都保存到Hive并以小时分区每小时调度一个Spark任务来处理两个表相应分区的数据做拼接由于是小时拼接实时性较低Spark作业本身也依赖于上游Hive表小时分区生成每个小时末尾的请求埋点有可能是落在当前小时也有可能落在下个小时。举个例子19点50分下发了一个视频客户端在19:59分点击了但是视频播放却是在20点03分完成的这个时候就会存在拼接不上的问题。图片2.2 基于 Redis 的流式拼接为了提升拼接率且达到实时拼接节点故障容灾完备监控等特性Flink是一个很好的替代方案也是最近几年比较主流的实现。最初在实时推荐场景中Kafka中的特征快照通过Flink任务写入到Redis另一个Flink任务消费曝光埋点数据和点击埋点数据并读取存在Redis中的特征快照数据做拼接拼接后的数据作为拼接特征被写入到下游的Kafka中提供给后续的算法做模型的训练架构图如下图片经过一段时间实践以上的方案出现了两个痛点Redis中存储了几十T的数据Redis的成本高业务数据流量会波动经常需要DBA对Redis集群进行扩容涉及大量数据的迁移运维成本高。2.3 基于 RocksDB 大状态流式拼接为了解决基于Redis的作为中间数据的存储存在的问题我们采用Flink状态来存储特征快照整个架构中不再需要外部的Redis由于我们需要存储的数据量达几十T这里我们选用适合大数据量存储的RocksDB类型的状态后端调整后架构更加简洁如下图所示图片流程如下首先将曝光流点点击流以及特征在Flink 任务中做union并做keyby在processElement方法中如果接收到曝光流就将数据保存到state中如果接收到曝光流就将数据保存到state中如果接收到特征就去state中查询相应的曝光和点击数据如果能找到就发送到下游并将状态数据清理掉没找到就将特征保存到state中并注册一个定时器定时器触发时去state中查询相应的曝光和点击数据如果找到就发到下游并将状态数据清理掉。由于RocksDB可以同时利用内存和磁盘来存储数据所以对于内存的使用量大幅下降由于RocksDB是嵌入式的数据库每个TM上的RocksDB数据库只存储shuffe到该TM上的数据无需再关注扩缩容的问题。当然随着数据上涨Flink流式拼接在实际的生产过程中也遇到了一系列的问题为了保证业务的可用性我们花了较长的时间对这些问题进行攻克目前任务稳定性达到99.99% 拼接率长期稳定在99%以上对拼接效果提升较大。下面我将列举我们遇到的问题和解决方案希望能够帮助到业内的其他团队。三、问题及解决方案3.1 TM Lost问题3.1.1 现象在方案实施之初我们发现这些特征拼接的任务频繁出现TM was Lost异常导致任务重启我们看了日志发现都是TM内存超出了YARN的内存限制被kill。3.1.2 问题分析那么我们的疑问就来了为啥这部分任务的内存很容易超出超出的那部分内存又是谁在用呢下面这张图是来自Flink的官网因为我们在平台使用Flink的时我们只设置了总的内存并没有关注其他各个局部的内存那么这些部位的内存是如何分配的为了搞清楚这个问题有必要梳理一下每个模块内存计算的逻辑。图片图片引用自FlinkFlink内存分配逻辑一般在YARN上提交的任务是含有taskmanager.memory.process.size 参数的配置的所以Flink在分配内存时会以调用deriveProcessSpecWithTotalProcessMemory 方法分配。通过配置参数获得meatspace 的大小通过jobmanager.memory.jvm-overhead.fraction 的比例计算overhead的内存totalFlinkMemory通过总的进程的内存减去meatspace overhead的内存得到。通过配置中的参数获取 frameworkHeapMemory-Size、frameworkOffHeapMemorySize 、task-OffHeapMemorySize 的大小。通过managedmemory的配置获取托管内存的值 通过networkbuffer的配置获取networkbuffer的值 。totalFlinkMemory 减去所有需要排除的内存剩下的内存分配给堆。内存分配逻辑以及每块内存的设置方法如下图图片到此TM的各个内存模块的内存已经划分完成。有上面的分析我们可以得出以下的结论totalProcessMemorySize totalFlinkMemorySize JvmMetaspaceSize JvmOverheadSizetotalFlinkMemorySize frameworkOffHeapMemorySize taskOffHeapMemorySize managedMemorySize networkMemorySize frameworkHeapMemorySize taskHeapMemorySize这里重点将一下JVMOverheadJVMOverhead并没有具体的作用是一个预留值它是一个缓冲区可以避免在Flink运行在容器中是因为短时时间的内存超出了容器的限制而被kill。frameworkOffHeapMemorySize和taskOff-HeapMemorySize 也是预留值offheap在概念上的主要是指native内存。frameworkHeap-MemorySize 也是预留值。由此可以看出虽然Flink官方将TM的内存划分的较细致但是像JvmOverheadSize frameworkOffHeap-MemorySizetaskOffHeapMemorySizeframeworkHeapMemorySize 都只是逻辑上的预留并没有从操作系统层面实现隔离。RocksDB内存分配逻辑因为堆内存不足时一般会报out of memory的异常所以到这一步我们推测应该是堆外内存溢出了而堆外内存最大的一块就是RocksDB使用的而从Flink的官网的介绍可以知道托管内存就是给RocksDB使用的下面我们再看一下托管内存是如何分配给RocksDB的。cacheMemory 1-1/3*writeBufferRatio* managedMemorybufferMemory 2/3*writeBufferRatio* managedMemory读写缓存总内存 bufferMemory cacheMemory 1 1/3*writeBufferRatio* managedMemory由上面的代码可以看出managed memory 是通过一定的比例给RocksDB的各个部分来分配内存的writeBufferRatio会影响读缓存和写缓存的大小理论上读写缓存总内存有可能会超过managedMemory的大小。通过上面的公式可以看出读写缓存总内存最多超出managedMemory的1/3这里很容易想到那么我们在排查overhead的时候配置大于managedMemory的1/3不就能你面内存溢出了但是在实践中我们这样配置并并没有完全的解决物理内存溢出的问题下面关于RocksDB内存的资料终于找到了是还有哪部分内存容易溢出了是因为部分区域的内存难以限制导致的。RocksDB 的内存占用有 4 个部分:Block Cache: OS PageCache 之上的一层缓存缓存未压缩的数据 BlockIndexes and filter blocks: 索引及布隆过滤器用于优化读性能MemTable: 类似写缓存Blocks pinned by Iterator: 触发 RocksDB 遍历操作比如遍历 RocksDBMapState 的所有 key时Iterator 在其生命周期内会阻止其引用到的 Block 和 MemTable 被释放导致额外的内存占用。前三个区域的内存都是可配置的但 Iterator 锁定的资源则要取决于应用业务使用模式且没有提供一个硬限制因此 Flink 在计算 RocksDB StateBackend 内存时没有将这部分纳入考虑其次是 RocksDB Block Cache 的一个 bug它会导致 Cache 大小无法严格控制有可能短时间内超出设置的内存容量相当于软限制原来是迭代器的内存限制的不好导致的内存溢出。3.1.3 解决方案我们在使用Flink 的RocksDB状态后端时是通过managed memory来控制RocksDB各个部分的内存的所以managed memory内存越小分配给各个部分的内存也就越小迭代器内存越不容易溢出。到此我们对Flink的RocksDB状态后端的内存有了一定的认知当性能可以满足的情况下Flink的Manaed memory应该越小越好。但是上满形成的经验很难高效的在业务上落地原因是“Flink的Manaed memory应该越小越好”很难去确定。于是我们联想到了之前的JVMoverhead在我们的实际实践中过程中我们是通过调大JVMoverhead和jemalloc内存分配器来解决内存溢出问题的。在Flink1.12之后Flink on k8s的内存分配器已经默认改成了jemalloc可以避免内存的分配过程中出现64M问题。但是要注意由于我们的Java版本是JAVA8小版本是192在最新版本的jemalloc5.3上出现了死锁的问题后来我们采用jemalloc4.5 就没有问题了。据了解业界有些公司使用的JAVA8小版本是256采用jemalloc5.3没有遇到死锁问题。3.2 RocksDB 的性能监控问题3.2.1 现象Flink RocksDB大状态的任务经常出现延迟但是我们很难知道性能的瓶颈在哪块从而优化响应的环节。3.2.2 解决方案其实Flink提供了一系列对于RocksDB的性能的监控指标我们只需要加上参数开启即可这里我只结局我觉得最有参考意义的指标开启的参数图片下面是相关指标的监控页面图片图片3.3 任务出现延迟3.3.1 现象Flink RocksDB大状态的任务经常出现延迟调优参数高达近百个如何系统性的调优难度较大。3.3.2 解决方案要想对RocksDB的性能做优化我们有必要先了解一下RocksDB的读写流程。RocksDB的读流程图片获取当前时刻的SuperVersionSuperVersion是RocksDB内针对于所有SST文件列表以及内存中的MemTable和Immutable MemTable的一个版本获取当前的序号来决定当前读操作依赖的数据快照尝试从第一步SuperVersion中引用的MemTable以及Immutable MemTable中获取对应的值。首先会经过布隆过滤器假如不存在则一定不存在反之假如返回存在则不一定存在尝试从Block Cache中读取尝试从SST文件中获取。RocksDB的写流程图片将写入操作顺序写入WAL日志中接下来把数据写到 MemTable中采用SkipList结构实现MemTable达到一定大小后将这个 MemTable 切换为不可更改的 immutable MemTable并新开一个 MemTable 接收新的写入请求这个 immutable MemTable进行持久化到磁盘成为L0 层的 SSTable 文件每一层的所有文件总大小是有限制的每下一层大十倍。一旦某一层的总大小超过阈值了就选择一个文件和下一层的文件合并。注意 所有下一层被影响到的文件都会参与 Compaction。合并之后保证 L1 到 L6 层的每一层的数据都是在 key 上全局有序的而 L0 层是可以有重叠的写流程的约束日志文件用于崩溃恢复每个MemTable及SST文件中的Key都是有序的字符顺序的升序日志文件中的Key是无序的删除操作是标记删除是插入操作的一种真正的删除要在Compaction的时候实现无更新实现记录更新通过插入一条新记录实现当任务出现延迟时由于我们已经有了RocksDB性能指标的监控也了解RocksDB的原理我们在做性能优化时就可以对症下药了。读性能优化当任务出现延迟且块缓存命中率下降时说明是读的性能下降导致延迟我们可以通过提升缓存命中率的方式来提升读性能RocksDB任务缓存命中率的优化思路如下托管内存小于TM内存20%可以调大托管内存state.backend.rocksdb.memory.managed 到 20%Flink内部对RocksDB的优化已经沉淀了多组参数建议使用配置state.backend.rocksdb.predefined-options SPINNING_DISK_OPTIMIZED_HIGH_MEMFlink中使用state.backend.rocksdb.memory.write-buffer-ratio参数来管理写缓存调小该参数能够提升读缓存该参数默认0.5RocksDB 会有一写索引和过滤器放在内存中用这个参数开启state.backend.rocksdb.memory.partitioned-index-filters 默认 false并且可以调节索引和过滤器占用的内存比例参数是state.backend.rocksdb.memory.high-prio-pool-ratio默认为0.1。写性能优化当任务延迟如果出现等待flush的内存表的大小增加或者等待合并的个数增加因为等带flush个数达到一定的个数时写将会被阻塞可以先关注一下磁盘io是否打满如果已经处于高位建议提升任务的并发。如果此磁盘io处于低位我们可以调整flush和compation的线程数来使写的数据不再积压。提升写写性能。Flink会将flush和compation的线程数通过一个参数统一管理参数是state.backend.rocksdb.thread.num默认值是1。3.4 任务启动慢的问题3.4.1 现象由于Flink任务在从状态启动时需要将存储在远程HDFS的状态文件读到本地当TM较集中时单台机器的磁盘io很容易被打满导致某些sub task 长时间处于INITIALIZING的状态。3.4.2 解决方案YARN参数的优化YARN默认的yarn.scheduler.fair.assignmultiple参数为flase即一次只分配一个container但是CDH将这个参数设置成了trueyarn.scheduler.fair.max.assigr默认为-1表示不限制所以导致一次调度到单个节点上的container较多。我们的解决方案是将YARN配置中的yarn.scheduler.fair.assignmultiple参数设为false一次只调度一个container解决了TM分配较集中的问题。Flink调度策略的优化由于只是限制了每次分配TM的个数还不能完全避免分配集中的问题于是我们对Flink引擎内部做了优化可以硬限制在某台机器上调度TM的个数具体做法是是当YARN返回给Flink ResourceManager container信息时判断container是否符合要求如果不符合可以部分拒收再次申请资源该功能由参数开启。图片3.5 磁盘打满的问题3.5.1 现象由于我们实时集群的磁盘较小大状态任务的状态达几十上百T频繁出现磁盘使用率达到90%的告警。3.5.2 解决方案我们将大状态的任务的Checkpoint数据存储到磁盘资源较宽裕的离线的集群非大状态的任务的Checkpoint数据存储在实时集群。3.6 HDFS RPC 飙高问题3.6.1 现象在业务新上一批任务后我们发现离线集群HDFS的RPC有明显的增加。图片3.6.2 解决方案由于我们默认只会保存最近的3个Checkpoint所以对于增量Checkpoint而言肯定会有文件的修改和删除据了解修改和删除是对HDFS性能影响较大的操作。我们对比这一批任务任务在HDFS上的Checkpoint文件和之前的任务对比发现文件数量大很多但是每个文件小很多于是我们调整了参数state.backend.rocksdb.compaction.level.target-file-size-base参数为256MB这个参数默认是64MB参数的作用控制压缩后的文件的大小。配置改参数后RPC回归正常。效果如图图片四、总结4.1 遗留问题4.1.1.RocksDB的调优的门槛较高虽然我们在任务上使用了积累通用经验进行优化但是有些数据量较大的任务在流量高峰期依然容易出现延迟RocksDB的参数有几十个要想把性能调优做到比较极致需要深入了解其原理还有对业务特点有深入的了解对于应用开发而言门槛较高。4.1.2.任务恢复慢由于有些任务的状态高达几十T在重启任务或者异常重启时要从Checkpoint恢复需要从远程的HDFS下载状态到本地磁盘单机的io很容易被打满虽然我们做了TM打散但是有些单个TM恢复状态就需要几十分钟这对于特征拼接任务来讲是不可接受的。4.1.3.SSD寿命消耗加速我们的实时集群磁盘使用的是单块的SSDSSD寿命是有限的然而RcoksDB的写放大的特点加速了SSD的寿命的消耗。4.2 规划经过较长时间的实践我们理解了样本拼接的本质是将不同来源、不同更新频率、不同规模的特征如基础特征、实时埋点特征、历史特征组合成完整样本而单一组件往往在 “延迟、存储规模、更新频率” 等维度存在短板必须通过混合架构实现 “优势互补”。业界混合架构的案例组件分工图片拼接流程① 实时日志采集用户点击商品的日志通过Kafka接入Flink实时作业② 实时数据存储将曝光流的数据存到RocksDB和HBase中RocksDB的TTL设置成1小时③ 算子内实时拼接Flink算子从RocksDB读取用户最近1小时埋点特征从HBase读取基础特征初步拼接成“实时基础”特征④ 历史特征融合Flink作业将初步拼接结果写入Paimon与Paimon中存储的“7天历史特征”融合生成完整样本⑤ 样本分发实时推荐完整样本通过Flink写入到HDFS提供给在线训练服务使用离线训练Spark作业从Paimon读取全量完整样本用于推荐模型的离线迭代。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询