登山则情满于山,观海则意溢于海。这篇文章主要讲述百度搜索中台新一代内容架构:FaaS化和智能化实战相关的知识,希望能为你提供帮助。
文章图片
一、背景搜索中台内容计算架构支持了数十个业务线的上百个检索场景,每个场景的数据都有一定的差异性,之前这些差异性都是由业务同学通过自定义的脚本进行独立开发。这些脚本存在开发成本高、维护成本高的情况,我们引入了业务框架+服务平台,实现了业务可以独立开发、自动部署和上线,同时代码库可以复用,一定程度上解决了开发成本和维护成本的问题。伴随业务快速发展,自定义入场开发的场景和诉求越来越多,在此过程中出现了以下问题:
- 学习成本大: 业务框架做了抽象,业务要上手开发需要学习完整的接入规范、开发规范,有的场景可能只要较少的业务代码开发,但是学习时间却要一周甚至更久,在新场景接入、尤其是简单业务场景,越来越多的情况下,学习成本变成了个棘手问题
- 资源成本高: 很多的业务场景有潮汐式特征,即每天只有一小段时间有内容计算,假设它只有1小时有,那么之前的架构浪费了23/24的资源,即另外23小时没有任何计算确占着资源,导致巨大的资源浪费
- 维护成本高: 搜索自身的复杂性,导致出现问题的时候开发者排查异常困难,有时候强依赖某些有经验的同学,整个系统的维护成本越来越高
二、思路与目标业界对于Serverless的大规模实践主要是聚焦于Web端应用,中后台的实践相对少一些。我们面对的场景是搜索中台数据的实时计算,而搜索本身又是非常复杂的业务。但是通过对我们场景的抽象与分析,我们具备了在中后台复杂场景实践Serverless/FaaS的可行性:
- 一方面,虽然业务开发的功能需求千差万别,本质上仍然有很多通用共性的地方。对于业务特定化的处理逻辑都可以将逻辑转化成一个一个的函数。而共性的功能可以通过抽象成通用组件。通过函数的编排和组件的复用可以乐高式搭建出适合业务的搜索数据计算系统。同时业务完全聚焦于业务自身逻辑中去,高可用、高并发、高扩展这些用户都不需要关注, 极大的简化的业务接入成本。
- 另一方面,由于业务流量的波峰波谷异常明显,通过深入业务层的智能化调度的实现,不仅可以提升业务在流量峰值的扩展能力,而且通过调度可以实现资源的充分利用,节约大量的资源成本。同时,针对越来越复杂的的系统,必然导致问题的排查恢复的成本也越来越高,通过智能化控制系统的引入,实时发现分析处理异常问题,使得整个系统更稳定更有韧性。
- 通过FaaS化建设,业务从聚焦于服务研发转变为聚焦于函数开发,全面的提升业务的开发效率。这里的FaaS化改造不仅仅说的是技术底座的变革,更是全系统全流程整体的业务效率的提升。
- 通过智能化建设,让架构系统根据服务的容量和状态进行动态调整,使得可以在追求更低资源成本的同时提供更高质量服务。智能化建设即包括从0到n极致化的智能伸缩调度,还包括根据系统的多维度实时状态信息进行智能分析自愈的智能控制系统。
文章图片
- 如上图所示业务在过去的普通云化服务中需要关注内容较多:从应用程序本身、组件和数据,以及服务的运行时环境,到最后的服务容器等基础设施的管理都需要业务方去关注。
- 当业务转变到FaaS化的思维中,业务需要开发处理的只是业务的一段逻辑表达,这里是以Function的方式表示, 其他部分(包括组件、数据、运行时环境和基础设施等一系列因素,业务甚至连原本应用程序本身)都不需要管理。
3.1 核心框架: 业务抽象与能力复用
核心框架是我们整个系统改造的基石,对业务来说主要包含两部分:
- 极致抽象的业务框架:是核心框架基础中的基础,提供新的开发范式同时,为后续智能调度奠定良好基础
- 高度复用的基础服务:强大丰富的后端服务能力封装,支持业务低成本复用,降低开发成本同时提升稳定性。同时系统还提供强大的编排能力,低成本支持业务从简单到复杂的发展
文章图片
业务端使用开发成本低的脚本语言进行开发(例如python),基础服务框架使用C++实现,通过架构层面的优化策略来达到服务性能和开发成本的平衡。
基础框架的发展本身经历了两个阶段:
- 阶段1:基础框架引擎使用C++实现(原来业务框架阶段基于脚本语言实现),架构代码与业务代码的充分解耦,直接调用业务函数代码,业务开发效率已经有了质的飞跃。
- 阶段2:为了规避脚本语言在进程中只能使用单核(如Python、php、JS等)特点,让业务函数具备容器内使用多核的能力,为后续支持极速扩容奠定基础。
- 流式计算框架: 我这边是直接基于百度StreamCompute流式计算框架开发,该框架原生支持基础流式计算数据流语义、支持拓扑函数的编排描述,为整个FaaS提供坚实的基础底座。大家实际使用过程中可以选取合适的流式计算框架开发。
- 数据预处理: 这里包含的功能比较多,从大体上协议解析、性能优化和数据观测等三个方面的工作
- 协议解析: 这里主要说明的框架的基础通信协议的定义解析,为了各业务数据通用性定义为 入参 和 出参均为原始字符串;
- 性能优化: 接入数据流框架本身,通过批量顺序读写、数据压缩的方式提高数据穿入过程中的服务吞吐;
- 数据观测: 进行基础指标汇报包括QPS、延时、内部队列等一系列信息,和异步的Trace信息(进入到Kafka中)。
- 进程管理&
服务管理: 并不在数据的主通道上,主要是应对整个容器内部进程和服务的管理。
- 进程管理: 伴生服务,负责启动、维护、销毁整个子进程的生命周期。
- 服务管理: 伴生服务,负责初始化并且维护远端的rpc 的client,修改访问参数,如超时、重试、下游访问策略等。负责新进程的创建、回收,以及进程间交互信息的维护。
- 进程通信异步数据分发: 这里有三个关键点: 数据不丢 、异常健全 和支持下游竞争消费。调研了包括数据管道通信、共享内存、系统队列和RPC等操作方式,考虑到稳定性、扩展性和实现成本等因素选择基于Baidu-RPC框架实现进程异步数据分发;
- 单进程模式: 当进程个数为1的时候则跳过进程通信,直接在本进程内部进行方法调用;
- 多进程模式:每个进程完全独立启动,业务视角隔离,但是公用一套业务代码环境。子进程处理完成后将请求结果反馈给父进程。
- 业务逻辑处理: 主要包括校验解析&
函数调用&
本地优化加速几部分,如上图左边就是业务逻辑处理的展开图。
- 解析&
校验&
优化: 每个线程内会进行参数解析协议校验,为了方便老业务迁移,支持多用户协议解析,线程并发优化;
- 执行引擎: 函数接口是真正函数调用地方,支持不同语言的调用引擎。eg: 如果业务使用Python,使用pybind。
- 数据提交: 执行完成后会统一推送到本地输出队列,本地队列里面的信息会异步提交到远端的消息队列里面给后续算子消费。
- 架构通用能力:包括索引算分(倒排、正排、向量索引),数据审核(政治敏感数据/色情数据识别&
过滤),多路分发、数据建库等能力;
- 与业务联合研发的能力:数据的低质过滤能力(实现数据清洗/归一化/数据去重/类目拼接),数据多元融合,数据质量打分计算(质量打分/作弊识别/物料打分)
- 基于公司强大基础能力: 多媒体处理服务(外链转内链/OCR/水印计算/重复图计算/主体识别/视频转储等),自然语言处理服务,数据沉淀服务
业务最开始接入通常只需要简单的少数功能(例如,修改部分字段的信息),多数业务直接用我们提供的平台化的开发模板即可完成开发。但是随着业务的逐步深耕,业务逐步使用,业务会向复杂逐步过渡,例如搜索中台某业务通过复用超过8种能力的组合使用,建设出具有深度定制的数据系统。
文章图片
3.2 全流程效能提升: 提供极简的用户使用体验
如3.1中提到的核心框架是FaaS化的基础但并不是全部。因为改造的底层逻辑是让业务聚焦于开发业务逻辑。这个过程不仅仅包括代码的开发阶段,而是包括从接入、开发、调试测试、上线维护的全流程阶段,因此我们需要对于系统进行全流程效能提升,才能最终保证业务的全面效率提升:
- 快速接入:权限申请到数据接入的全面简化。简化的建设主要是两方面思路:其一是流程上的简化(例如: 权限申请流程无需架构同学参与,组内同学就可以审批处理);其二开发过程的简化,对于常见的流式数据系统(公司其他中台或者官方数据系统) &
通用存储(常用的公司数据存储 eg mysql、Mongo、公司内部的表格存储甚至原生FTP本地文件) 支持配置化的批量导入。同时我们也提自定义(完美适配Docker)的任务系统提供做够的灵活性保证业务的低成本接入;
- 极速开发:平台完善函数内容。我们这边开发有两种模式,一种适合初学者的Air模式,一种是适合高端玩家的Pro模式;针对于Air模式本身,用户可以直接在平台完成代码的提交和调试功能,完全一键处理;
文章图片
文章图片
- 快速调试&
测试:业务可以根据自己实际的需要可以通过平台化的方式调试通用的模板函数, 也可以通过线下集成调试环境一体化的对整个系统进行调试。针对于测试提供了平台化的测试方案,业务可以默认0配置的情况下进行服务性能和执行数据结果的DIFF;
- 问题定位: 这部分对于业务问题解决尤为重要。主要包括监控报警和云日志两部分功能(具体架构设计在2.1可观测性建设 中有详细的描述):
- 监控报警:包含两部分信息通用部分和业务自定义两部分。其中通用部分提供 包括算子总体堆积程度,每个算子的处理的信息,app 实例状态 等等20多项常用数据指标,直接集成到管理平台内部,可以不需配置直接使用。而自定义部分提供了基础的SDK函数装饰器,可以极低成本给监控自定义代码段的成功率,延时等信息;
- 云日志:包含数据Trace(数据流向)、日志Trace以及相关的数据报表服务,业务都可以极低成本进行服务接入。
四、智能化:追求更低成本、更高质量的服务通过上一部分提到的FaaS化改造,业务的全流程服务效率问题得到巨大的改善。接下来通过智能化改造的工作在避免大量资源浪费、降低资源成本的同时,提高业务的服务质量。智能化的工作主要包括两部分:
- 通过智能化的资源调度方案,极大的节约用户的资源成本,真正做到按需使用,而且可以有效处理流量洪峰,提高系统稳定性。
- 通过智能化的控制架构,有效处理异常问题,做到问题主动感知、决策并且主动处理,提升系统韧性的同时降低大量的维护人力成本。
4.1 智能调度: 极致化弹性伸缩
过去,业务的app主要配置固定容量配置,我们多数的业务流量都有明显的潮汐式,大量业务天级别只有1个小时,甚至几分钟的流量,这样就造成了大量资源浪费。
智能调度的核心作用就是实现业务的资源的按需分配, 实现从0→n的资源满足,具体上来讲主要有如下功能:
- 自动伸缩:根据当前服务流量的波动情况自动分配出来对应可以满足整体实例消费情况的实例数进行消费,包含纵向本地扩容+容器横向伸缩的方式相结合多阶段扩容;
- 服务资源回收&
冷启动:保证长时间没流量的服务容器,资源完全被回收,不占用任何服务资源,当新流量资源到来的时候,服务接着过去资源的数据消费,保证数据生效稳定性的同时,使得业务完全做到按需使用;
- 异常实例迁移:主要通过热点实例迁移,长尾实例迁移保证服务全局的正常运行;
- 容器资源自适应:主要通过检测内存使用状态,对资源容器进行自适应的调整,保证容器资源在不浪费的同时,保证服务不会超限而造成服务的OOM。
设计思路:多阶段扩容的设计原因扩缩容最初只有传统意义上的横向扩缩容,在我们的业务场景下可以达到分钟级的是时效性,多数业务可以满足需求。然而,针对于高时效业务,当流量高峰突然到来的时候(例如3倍过去高峰流量),分钟级的扩容速度业务无法接受。为了解决这个问题一般只能给一定业务流量BUFFER(比如2倍流量)。如果资源BUFFER充足,业务方则有大规模的的资源浪费,如果资源BUFFER不足时效性依然没有完全解决。
其实业务的核心诉求是架构能否做到相对稳定的秒级伸缩。可以快速缓解业务流量洪峰的压力,提高系统稳定性扩展性的同时达到最佳的资源利用。通过分析横向扩缩容底层现状我们发现:
- 启动时间分析: _容器的调度时间+rumtime初始化时间_占据了整个启动时间的98%以上,一般需要5分钟,依赖于公司基础PaaS环境,优化成本非常高;
- 开发业务:业务都是通过脚本语言开发(通常是Python),受到解释器限制极限只能用满CPU单核, 有时甚至由于业务代码逻辑问题远远无法达到;
- 资源占用:容器规格很小(CPU规格极小、容器内存资源充足),多数机器上的剩余quota足够。
结合3.1核心框架中提到的多进程框架的实现,实际扩容包含两个阶段:
- 纵向本地扩容阶段:可以满足在高时效业务场景下突发流量到来的极速资源满足速度,通常可以瞬间满足5~10倍的资源。此外,扩容过程中是允许少数实例纵向扩容失败的,通过流量均匀分发的能力,将纵向失败的流量实例流量均摊到成功的实例上。
- 容器横向伸缩阶段:两种情况会进行横向扩容阶段:
- 其一,当高峰流量持续时间较长(一般超过10分钟)时,会进行横向扩容实让服务容器分裂(例如:2个实例_10进程 → 20个实例_1进程);
- 其二,纵向扩容后仍然不能完全满足吞吐要求(例如100倍的服务吞吐需求),则会在纵向扩容后瞬间触发横向扩容,不过此时业务完全满足效率退化成分钟级。
核心实现: 调度核心架构如下图是我们智能调度简化架构图:
文章图片
主要分成下面几个阶段:
- 采集层: 采集数据的基础信息,这里主要需要集中类型的信息,尤其是扩缩容其实主要关注两个队列信息:
- 数据流的队列信息
- 流式算子之间的队列信息
- 决策层: 根据历史调度信息和当前的实际状态信息进行决策,实现多阶段可变步长的扩容:
- 优先进行本地扩容,根据当前容器的资源使用量最多需要平均可以扩容5→20倍
- 长时间当本地扩容到(或者接近)极限,则会进行横向扩容,这个资源水平没有特殊限制
- 多阶段: 本地扩容(纵向) + 横向扩容
- 可变步长: 数据堆积都有多个阈值,每个阈值关系到不同的步长(默认每个APP至少两个步长)。eg: 政务业务的数据流堆积1000持续超过30s则触发扩容1倍,如果超过10000,则直接扩容到最大实例数
- 分析层: 在整体资源低于阈值(默认85%)的时候默认是跳过该阶段;在整体资源超过阈值后,为了保证高优先级的资源进行优先级调度使用的,必要的时候会对低优任务进行淘汰
- 执行层: 根据决策分析层提供的信息执行
- 本地扩容: 直接调整容器Quota信息的同时基础框架的进程管理启动服务的进程数来实现本地的极速扩容(比横向扩容快一个数量级)
- 横向扩容: 普通横向调整实例个数,由于涉及到资源调度,数据环境的初始化,需要的时间周期是分钟级
- 过滤: 扩容生效都有一个时间周期(本地扩容秒级,横向扩容分钟级),每个决策后都有一个静默期(比如10分钟)从而避免重复决策执行
- 跳档: 过滤只针对于完全相同的操作拦截,针对于不同步长扩容不拦截,保证业务在流量洪峰下的感知执行速度
- 执行: 真正执行操作,例如扩缩容操作
按需计费的实现考虑到不同业务有不同的调度逻辑和配置场景: 有的业务需要资源预留(保证最低实例数), 则这部分业务有最低资源占有成本;而多数业务没有特定的需求,一般冷启动延迟业务可以接受,则不需要保证最低实例数; 有的业务需要时效性要求比较高,扩容敏感度高,缩容敏感度低, 而对于普通扩容敏感度,甚至敏感度更低的业务,相同状况下扩容的资源数可能完善不一致; 有的业务不需要容器自动适配,而多数业务需要在容器尤其是内存设置不合理的时候主动获取更大的容器。业务实际上的收费就是按照业务不同的调度策略进行计费,真正做到不多不漏,合理计费。
通过智能调度服务实现了核心生产环境多数场景支持秒级自动伸缩, 支持0→n的极致扩容。按需计费,整体资源节约87%。
4.2 智能控制: 防止问题升级扩散,全自动实时处理
智能化调度实现了极致化的弹性伸缩,做到了资源的极大节省。我们的整个系统也随着系统云原生化的改造下变得越来越复杂,但是问题的排查成本却越来越高。因此问题的排查通常需要多个方向的同学通力合作(或者依赖个别专家同学的定位)才能处理解决。这不仅仅是对架构人力的巨大浪费,而且干预时间常常不可控,对于线上有很大风险。为了解决这个问题,搜索中台内容生效架构引入了智能控制系统, 快速、准确的发现问题、处理问题并且整个过程是完全自动化的:
- 快速: 处理速度快,主动发现 与 消息通知相结合的方式,全面进行问题排查
- 准确: 历史出现过的问题转化成系统规则,整个过程模拟专家进行处理解决。只要规则合理,没有误操作,没有非预期行为
- 自动: 处理过程完全无需人工干预,全程自动化处理
文章图片
通过整体系统的执行自愈的连续迭代调整, 最终让系统调整到一个健康的状态。
完善可观测系统(基础)
可观测系统并非此次叙述的核心,但是它仍然是智能控制的基础。没有完备的可观测系统建设,一切有效的控制系统都是空谈,如下图就是整体可观测系统的概览:
文章图片
- 基础采集层: 为所有的观测系统的数据提供最原始的基础数据采集。从数据类型来分主要是三类:
- 流式数据: 需要记录每条数据的信息,主要借助于Kafka的数据队列收集
- 指标数据: 对外汇报每个实例的指标数据,对外exporter汇报数,或者直接原始公司公司内的监控系统进行采集
- 自定义数据: 这种一般使用脚本以特定化的方式采集,作为基础指标采集的补充
- 数据处理层: 该层主要是针对于流式原始数据的数据处理,从图中可以看到主要是两部分数据,很多基础数据信息不需要额外聚合
- 指标聚合层: 主要是提供于拓扑分析系统,这里基于StatsD和Prometheus的转换接口,实现的指标动态分桶机制,极少资源完成大量数据信息
- 数据聚合层: 主要提供于实时成功率监控系统,这里是基于数据的动态Hash和流式计算完成的
- 存储层: 该层是可观测系统的中间核心,这里我们用到的数据存储既有开源的系统(包括ES/Prometheus/Mongo等),也有公司内的监控系统(以复用为主)。有两个大系统提供原始数据:
- 一方面,给上层应用系统提供数据展示的原始数据;
- 另一方面,给智能控制提供决策的原始数据。
- 展现层: 用户直接访问的前端接口,这里有我们自定义的平台,也有直接借助开源系统Grafana和Skywalking之上进行建设
- 应用层: 用户或者是架构所需的对外查看的系统,有6大业务系统,包括:
- Trace系统: 包括数据Trace 和 日志Trace,确认任意单条数据信息
- 指标系统: 最关键的基础数据信息,所有架构层和业务层的核心指标都收录于此
- 健康刻画系统: 通过当前全局的报警信息(报警级别、时间、个数)刻画出整体当前系统的健康程度
- 拓扑分析系统: 分析业务侧面和架构侧数据流是否存在异常(数据流量变化,异常点分析)
- 效果监控系统: 从数据生效结果监控,从架构效果端反推业务问题,比如 监控关键数据变更的时间戳反推架构系统问题
- 实时成功率监控: 查看数据流整体端到端的实时成功率信息
健全的自愈能力建设(手段)完善可观测性提供决策的数据源,它是智能控制的基础。而自愈能力的建设是自动化的控制的重要手段,否则依赖纯人工干预(例如”手动删除一个实例” 或者 “线上修改一个配置”)的操作是没办法实现自动化和快速止损的。自愈能力建设这里重点描述所覆盖的功能集合,不仅仅包含我们传统意义上的容器管理功能(例如:实例重启、迁移等),还有深入到业务系统架构中的服务管理类和通路控制类的功能:
- 服务管理类: 主要是基于资源&
服务的管理,包括通路切换(主备切换,优先级切换)、数据拦截、数据回灌 和 服务降级 等
- 通路管理类: 主要是基于提供基础组件的管理功能, 包括流量清理、查询拦截(异常查询& 慢查询查杀)
- 阶段1: 传统配置化的规则引擎的配置(上图中右上角黄色部分),配置多个采集指标项的逻辑关系(与或交非), 这里主要是针对问题的基础分析功能,判定规则是否触发。
- 阶段2: 基于这个基础分析的结果,进行后置Function的执行分析,这个主要是针对复杂问题的分析补充, 最终执行引擎根据这个返回结果进行函数执行。
文章图片
- 前提: 开发者需要配置好处理逻辑规则(以及规则依赖的数据项,必填) &
回调函数(选填)。
- 数据解析器: 数据解析器主要承担的数据的原始抽取的工作,一共分成如下3步;
- 配置解析: 逻辑执行根据开发者配置的数据信息解析;
- 数据抽取: 根据解析出来的配置通过数据接口进行获取,可以从统一接口根据配置的信息从不同的介质充抽取所需求的信息;
- 数据归一化: 将不同介质的原始数据归一化成为统一的数据格式供规则管理器使用。
- 规则管理器: 规则管理器主要承担核心的逻辑分析工作,一共分成如下几步:
- 规则解析: 根据开发者配置的规则逻辑,将原始配置信息,解释成原始的规则树;
- 执行计算: 根据数据解析器提供的数据结果和配置的函数规则分别执行计算。执行计算过程中最重要的就是基础分析器,整体提供了5大基础能力,数十种常见的逻辑计算来辅助规则配置。
- 规则逻辑运算: 根据上层解析出来的规则树 和 每个数据项执行完成的计算结果进行逻辑运算,并根据执行的结果确定是否进行高级数据分析器,如果判断结果为真则根据所配置的后置函数进行处理;
- 高级数据分析器: 如图所示有两种模式,对于简单基础分析可以判断结果的,直接给默认的处理函数进行数据拓传;对于简单逻辑规则无法准确表达的,开发者可以自定义后置分析函数, 函数会将原始数据和基础计算的计算结果作为参数传出来,开发者只需要通过处理后的数据描述清楚分析逻辑即可;
- 动作执行器: 就是这个分析器的真正的执行引擎,根据规则运算的结果中包含的参数进行动态调整。
五、总结整体的工作思路以Serverless为指导思想,通过FaaS化 和 智能化两个维度的系统化建设,以技术手段系统性实现了降本、增效、提质:
- 通过FaaS化的建设,提升基础服务性能的同时全流程服务效率的提高, 具体来说包括两部分:
- 打造新一代的核心框架,提供强大的基础底座让业务核心关注点从原来的云化服务思维聚焦到逻辑实现,业务通过简单复用和编排实现复杂的功能,让业务开发更简单
- 提供一体化全流程系统建设,让业务从接入、开发、调试测试到最终系统维护全流程的流畅体验,助力业务更高效的交付
- 通过智能化建设,在稳定性有巨大提升的同时大幅度降低资源成本和系统的维护成本,具体来说也包含两部分:
- 通过智能化调度, 实现业务的按需分配(0→n), 秒级应对突发流量, 节约大量的资源成本;
- 通过智能化控制,实现全系统绝大多数问题问题的自动感知、自动分析、自动处理,提升稳定性的同时降低了系统的维护成本。
推荐阅读:
当技术重构遇上DDD,如何实现业务、技术双赢?
接口文档自动更改?百度程序员开发效率MAX的秘诀
技术揭秘!百度搜索中台低代码的探索与实践
百度智能云实战——静态文件CDN加速
化繁为简--百度智能小程序主数据架构实战总结
百度搜索中台海量数据管理的云原生和智能化实践
百度搜索中“鱼龙混杂”的加盟信息,如何靠AI 解决?
---------- END ----------
百度 Geek 说
百度官方技术公众号上线啦!
技术干货 · 行业资讯 · 线上沙龙 · 行业大会
招聘信息 · 内推信息 · 技术书籍 · 百度周边
欢迎各位同学关注
推荐阅读
- Flutter 专题54 图解基本生命周期 #yyds干货盘点#
- HttpServer: 基于IOCP模型且集成Openssl的轻量级高性能web服务器
- #yyds干活盘点# 1.21 HTML5表单属性
- Kubernetes官方java客户端之四(内部应用)
- 1.3-1.9博客精彩回顾
- 闯祸了,生成环境执行了DDL操作《死磕MySQL系列 十四》
- #yyds干货盘点#PHP实现定时任务hellogerard/jobby实例
- Bootstrap实战 - 响应式布局
- #yyds干货盘点# 阿里四面(kafka何时如何删除Topic())