Netflix 网飞的架构演进过程、Java在网飞中的应用|图解

发布于:2025-07-01 ⋅ 阅读:(16) ⋅ 点赞:(0)

写在前面

上一篇文章中,我们讲解了网飞当前的架构,但网飞的架构并不是一开始就是这样的,而是不断演进发展才是当前的样子。
在这里插入图片描述
这篇文章我们就来讲讲网飞架构的演进过程。

第一阶段:Zuul Gateway + REST API

  • 使用 Zuul 作为API网关,单一前门
  • 设备调用网关,网关扇出到多个微服务
    Netfile 第一版架构

而在这个架构下,会遇到一些问题:

  • 不同设备有不同的数据需求,Web端、App端、TV端所需要的数据结构不一样
  • 单一REST API无法满足所有设备,导致api变多且难以维护,要么获取过多数据,要么需要多次调用
  • 设备特定的优化需求难以进行

第二阶段:BFF(Backend For Frontend)模式

为了处理不同设备的差异化数据需求和减少网络调用,网飞采用了Backend For Frontend (BFF)模式。每个前端都有专属的后端。

  • UI开发者编写和维护 Groovy脚本定制化获取数据。
  • Groovy 脚本部署在API服务器上,通过 Java 调用gRPC/REST服务,并使用 RxJava 和容错库 Hystrix 处理扇出中的线程管理和容错问题

Groovy 是 ‌后端导向的语言‌,主要服务于 JVM 平台的后端逻辑、自动化脚本和构建工具链

在这里插入图片描述
然而,这种 BFF 模式存在局限性:

  1. 需要维护大量的脚本,每个终端一个脚本,维护复杂。
  2. 反应式编程本身学习曲线陡峭且复杂
  3. UI 开发者不喜欢用 Groovy/Java/RxJava

第三阶段:GraphQL Federation + Java Version 21

  • 采用DGS微服务:基于 GraphQL 的 SprintBoot 服务
  • API 网关处理GraphQL

GraphQL Federation 取代了 BFF,因为客户端可以通过 GraphQL 精确选择所需的字段,解决了 REST API 过度或不足获取数据的问题,使得一个 API 可以服务于不同的 UI。这意味着 UI 工程师不再需要进行服务器端开发来获取自己所需要的数据。

在这里插入图片描述

Java 版本升级

从 Java 8 迁移到 Java 17 后,得益于G1垃圾收集器的改进,CPU 使用率降低约 20%,这是一个非常恐怖的优化,会省下非常多的云资源。这些jdk的升级其实很难做,需要兼顾每一个第三方包。是一项很繁琐的工作。

举个视频中的例子,网飞处理Spring Boot 3升级中的Jakarta EE 命名空间的变化,Spring Boot 3 是基于JDK 17,并且从javax切换到了jakarta.ee。对于应用程序而言,这只是简单的查找并替换。
在这里插入图片描述

但对于依赖 javax 并且已经编译成JAR包的老旧库来说,而这些老旧库已经找不到源代码了但还在使用,运行时仍然会尝试寻找 javax.servlet.Filter。但此时,环境提供的却是 jakarta.servlet.Filter。由于包名和类名不匹配,即使功能相同,JVM也无法找到对应的类,从而导致运行时错误。

针对这种二进制不兼容性的情况,Netflix利用 Gradle transforms 来解决。通过 Gradle插件工具,在依赖包下载时的 artifact resolution time 进行字节码重写相当于二进制的查找并替换,将所有javax 替换为 jakarta。

在这里插入图片描述
由于这些API在功能上没有变化,只是命名空间改变,所以这种重写是安全的。而这个工具已作为Netflix Nebula生态系统的一部分开源。
在这里插入图片描述

此外网飞目前正测试和推广 Java 21+,Java 21+ 的 ZGC 垃圾收集器(低暂停时间)和虚拟线程(Virtual Threads)特性都非常优秀。 虚拟线程结合结构化并发很有可能完全取代反应式编程(如 RxJava),简化并发代码的开发和调试。