字节Tiktok后端三面,一周出结果已约hr面

字节Tiktok后端三面,一周出结果已约hr面
最新回答
言笑往事

2026-07-08 03:38:11

字节TikTok后端三面整体围绕技术深度、系统设计能力和底层原理展开,涉及实习经历、时序数据库、八股文及算法题,已通过技术面并进入HR面流程。 以下是对面试内容的详细解析:

一、实习经历相关
  • 工作内容:面试官关注实习期间具体承担的任务,例如是否参与过核心模块开发、是否解决过复杂问题、是否对业务有深入理解等。需结合具体项目,说明自己在需求分析、方案设计、编码实现、测试优化等环节的贡献,突出技术能力和工程素养。
  • 时序数据库场景:时序数据库主要用于处理带时间戳的连续数据,典型场景包括:

    监控系统:如服务器性能指标(CPU、内存、网络流量等)的实时采集与存储。

    物联网(IoT):传感器数据(温度、湿度、压力等)的长时间序列存储与分析。

    金融交易:股票价格、交易量等高频数据的实时记录与回溯。

    日志分析:系统日志、用户行为日志等时间序列数据的聚合与查询。

  • 时序数据库架构:通常采用分层架构,包括:

    数据采集层:通过Agent或SDK收集数据,支持高并发写入。

    存储引擎层:负责数据的持久化存储,采用列式存储、压缩算法(如Gorilla、ZSTD)和索引技术(如倒排索引、时间线索引)优化存储效率和查询性能。

    查询引擎层:支持SQL或专用查询语言,提供时间范围查询、聚合计算、降采样等功能。

    管理服务层:包括集群管理、元数据管理、监控告警等模块。

二、时序数据库技术细节
  • 列式存储优势:

    高压缩率:相同类型的数据连续存储,便于应用压缩算法(如Delta Encoding、Run-Length Encoding),减少存储空间。

    高效查询:针对聚合查询(如SUM、AVG)或范围查询,只需读取相关列,减少I/O开销。

    适合时序数据:时序数据通常按时间戳和指标值存储,列式存储能更好地支持时间范围查询和指标聚合。

  • 列式存储按行读取:

    通过行号映射或元数据索引定位到目标行的所有列数据。

    读取时需将分散的列数据拼接成完整行,可能引入额外开销,但可通过缓存或预取优化。

  • 列式统计信息:

    包括每列的最小值、最大值、平均值、分位数、直方图等,用于查询优化(如跳过无关数据块)和结果估算。

    统计信息通常由存储引擎在数据写入或压缩时更新。

  • 类LSM架构的Compaction:

    LSM树:将数据分为内存中的MemTable和磁盘上的SSTable,通过后台Compaction合并SSTable,减少查询时的I/O。

    Compaction策略:包括层级式(LevelDB)、大小分级式(RocksDB)等,目标是最小化写入放大和查询延迟。

    时序数据库中的优化:针对时序数据的时间局部性,可采用时间分区或时间线分区的Compaction策略,优先合并相邻时间范围的数据。

  • Prepared Statement:

    预编译SQL语句,将参数化查询与执行计划分离,提高查询效率和安全性。

    优势包括:

    减少解析开销:SQL语句只需解析一次,后续执行直接使用预编译计划。

    防止SQL注入:参数通过占位符传递,避免恶意拼接SQL。

    提升性能:数据库可缓存执行计划,重复执行时跳过优化阶段。

三、乱序数据处理与算法
  • 乱序数据处理方案:

    缓冲窗口:设置时间窗口(如5分钟),将乱序数据暂存于内存或磁盘,待窗口关闭后统一处理。

    版本控制:为每个数据点添加版本号或时间戳,查询时按版本排序或合并。

    Merge_Reader实现:

    维护一个优先级队列(如最小堆),按时间戳排序数据流。

    从队列中取出最早的数据点,若与前一个数据点时间重叠,则根据业务规则(如取最新值、求和、平均)合并。

    处理后的数据写入输出流,并继续读取后续数据。

  • 时间重叠下的统计信息:

    若统计操作(如SUM、COUNT)支持重叠区间,需明确合并规则(如加权平均、最大值覆盖)。

    若统计操作不支持重叠(如UNIQUE COUNT),需先去重或按时间分区计算。

四、八股文与底层原理
  • Redis:

    若不了解,可诚实说明,但可补充对缓存、数据结构(如String、Hash、List)或持久化机制(RDB、AOF)的基本认识。

  • Fork与Copy-On-Write:

    Fork:创建子进程时复制父进程的页表,但共享物理内存,仅在写入时触发Copy-On-Write(COW),避免不必要的内存拷贝。

    应用场景:如Linux的fork()系统调用、Redis的RDB持久化(通过fork子进程生成快照)。

  • a = fork(), b = fork(), print(a, b)输出分析:

    第一次fork()后,父进程和子进程分别执行,a在父进程为子进程PID,在子进程为0。

    第二次fork()时,父进程和子进程各自再fork,b的值取决于当前进程是父进程的子进程还是子进程的子进程。

    输出可能为:

    父进程:a=子进程PID, b=孙进程PID

    第一次fork的子进程:a=0, b=孙进程PID

    第二次fork的子进程(父进程的孙进程):a=0, b=0

  • 内核态Context Switch开销:

    包括保存/恢复寄存器状态、切换页表、刷新TLB、调度算法计算等,通常需微秒级时间。

    开销来源:

    CPU缓存失效:切换进程后,CPU缓存需重新加载新进程的数据。

    TLB刷新:页表切换导致TLB命中率下降,增加内存访问延迟。

  • Kernel Bypass示例(SPDK):

    SPDK(Storage Performance Development Kit):用户态存储开发套件,通过DPDK(Data Plane Development Kit)实现零拷贝、无锁队列和轮询模式,绕过Linux内核的存储栈(如块设备层、文件系统层),显著提升I/O性能。

    应用场景:高性能存储(如NVMe SSD)、分布式存储系统(如Ceph)、数据库存储引擎等。

五、算法题:单链表归并排序
  • 时间复杂度:

    归并排序的时间复杂度为O(n log n),与数据分布无关。

    在链表实现中,合并两个有序链表的时间复杂度为O(n),共需log n层合并,因此总时间复杂度为O(n log n)。

  • 实现步骤:

    分割链表:使用快慢指针找到中点,将链表分为两部分。

    递归排序:对左右两部分递归调用归并排序。

    合并链表:合并两个已排序的链表,返回新链表的头节点。

  • 代码示例(伪代码):
def merge_sort(head): if not head or not head.next: return head # 分割链表 slow, fast = head, head.next while fast and fast.next: slow = slow.next fast = fast.next.next mid = slow.next slow.next = None # 递归排序 left = merge_sort(head) right = merge_sort(mid) # 合并链表 return merge(left, right)def merge(l1, l2): dummy = ListNode(0) curr = dummy while l1 and l2: if l1.val < l2.val: curr.next = l1 l1 = l1.next else: curr.next = l2 l2 = l2.next curr = curr.next curr.next = l1 if l1 else l2 return dummy.next六、面试结果与建议
  • 结果:已通过技术三面,进入HR面流程,通常HR面会关注职业规划、团队匹配度、薪资期望等非技术问题。
  • 建议:

    提前准备HR面常见问题(如“为什么选择字节跳动”“未来3-5年规划”)。

    复盘技术面中的不足,如对某些知识点(如Redis)的掌握不够深入,可后续补充学习。

    保持沟通顺畅,及时确认HR面后的后续流程(如Offer发放时间)。