图解 Netflix 网飞架构|技术栈、DGS、Java
作者:微信文章写在前面
前段时间在网上刷到一个视频 《How Netflix Uses Java - 2025 Edition》
How Netflix Uses Java
看完觉得还挺有意思的,于是想写一篇文档share一下,一起交流学习。当然由于本人的英语能力有限,Java理解缺乏,有错的地方欢迎大家指出来。 也推荐大家看看网飞的技术博客网址,里面很详细的介绍网飞的各个中间件的使用,链接都放文章的最后。
整体架构
Netflix ArchitectureC 端流媒体
网飞作为全球最大的流媒体平台之一,QPS极高,用户数以百万计。服务部署在多个 AWS 区域(四个不同的亚马逊区域)以降低网络IO延迟。
整体架构采用常见的微服务架构,拆分成各个子模块进行单独维护。流媒体部分通常对失败通常可以进行重试,即使部分数据丢失,应用整体仍可工作。而为了更快的速度,会使用基于的内存分布式数据存储。下面我们一个个模块拆分讲解:
Client 模块
这个模块涉及多端开发:
IOS端:SwiftAndroid端:KotlinWeb端:React
和大多数公司的技术选型一样,猜测也可能会有RN这种跨端的存在。
API Gateway 模块
这是所有来自客户端请求的单入口,主要处理 GraphQL 请求。
网关接收到 GraphQL 请求根据 federated schema 将请求分解:将一个大的schema请求查询,拆分成多个小查询,以便下一步请求后端服务向多个后端的 DGS 微服务发起请求:并发请求后端多个微服务服务
GraphQL:Facebook 开源的一款API查询语言
客户端可以精确指定需要的数据结构和字段,避免 REST API 中常见的数据过度获取(Over-fetching)或数据不足(Under-fetching)问题。 这也是Netflix放弃了REST 的原因之一。
举个例子:假设我们有一个图书管理系统,需要查询书籍及其作者信息。
REST API :多次请求、数据冗余或不足。
获取书籍列表:GET /books(返回所有书籍字段,但客户端可能只需要书名)获取某本书的作者详情:GET /books/{:id}/author(额外请求,N+1 问题)
GraphQL:只需发送一次请求,精确指定需要的数据
客户端发送:
query {
book(id: "1") {
title
releaseYear
author {
name
country
}
}
}
服务端返回:
{
"data": {
"book": {
"title": "xxxx",
"releaseYear": 2000,
"author": {
"name": "xxxxx",
"country": "xxx"
}
}
}
}
Fanout 扇出
一种并发编程模式,指的是从一个入口点同时向多个目标发送请求或数据的过程。就像扇子展开一样,一个请求"扇出"到多个服务或资源。
核心特征:
并发执行 :多个请求同时发出,而不是串行执行聚合结果 :等待所有请求完成后,将结果合并返回性能优化 :总响应时间接近最慢的单个请求,而不是所有请求时间的总和
fanout 扇出DGS 模块 Domain Graph Service
Domain Graph Service 是 Netflix 开发的 GraphQL 框架,基于 Spring Boot 构建。每个 DGS 本质上是一个独立的 Java 微服务,但具备 GraphQL 能力。
从上面我们知道网关接收到 GraphQL 请求后,会根据 Federated GraphQL 规范进行扇出(fanout)操作。这意味着网关会调用多个后端服务来获取完成 GraphQL 查询所需的数据。这些后端服务被称为 DGS (Domain Graph Service)。 各个微服务之间使用gRPC进行通信。
核心特点
独立微服务 :每个 DGS 都是完整的微服务,包括部署、扩展和生命周期GraphQL Endpoint 端点:提供 GraphQL API 接口 Schema 定义:定义自己负责的 GraphQL 类型和字段类型扩展 :可以扩展其他服务定义的类型
举个例子:假设网飞有个用户服务DGS,观看历史服务DGS
用户服务(User Service DGS):定义用户基础Schema
# User Service Schema
type User @key(fields: "id") {
id: ID!
email: String!
name: String!
createdAt: DateTime!
}
type Query {
user(id: ID!): User
users: !
}
观看历史服务(History Service DGS):扩展 User 类型,添加观看相关字段
# Viewing History Service Schema
extend type User @key(fields: "id") {
id: ID! @external
watchHistory: !
currentlyWatching: !
watchTime: Int! # 总观看时长(分钟)
favoriteGenres: !
}
type WatchRecord {
contentId: ID!
watchedAt: DateTime!
progress: Float! # 观看进度 0-1
rating: Int # 用户评分 1-5
}
type Content {
id: ID!
title: String!
}
这时客户端发送一个统一的查询,就可以获取来自多个服务的数据:
query GetUserProfile($userId: ID!) {
user(id: $userId) {
# 来自 User Service
name
subscription
# 来自 Viewing History Service
watchTime
favoriteGenres
currentlyWatching {
title
type
}
}
}
这些 DGS 彼此无需了解,只需向 Federated Gateway 发布它们的 Schema。而 Gateway 是知道如何与 DGS 通信,因为它们都有 GraphQL 端点。
⚠️ 注意:这里是 Endpoint 端点,不是端口 Port
DataStore 模块
data store 数据存储
存储模块其实还有很多,我这里大概讲讲几个重要的:
关系型数据库PostgreSQL、MySQL:主要存储Netflix 平台的各种数据,包括用户数据、节目信息、订阅信息以及账单交易等。非关系型数据Cassandra:存储用户观看历史数据。这是一种 NoSQL 数据库,具备强大的时序数据处理能力、可扩展性、高可用性和快速读写性能,非常适合时序数据的存储。EV Cache:网飞自研的一个基于Memcached的内存存储的开源、快速的分布式缓存。用于缓存例如电影、电视剧的标题、描述、用户的在线状态等等。BigSearch:基于ES的一个图关系搜索,为了实现 GraphQL 架构中跨服务的复杂查询(虽然不叫bigsearch,我这里就随便命名了一个)Kafka+FlinkCDC:数据库变更后,通过CDC连接器触发Kafka事件流更新ES中的索引信息。AWS S3:亚马逊云服务提供的对象存储服务,用来存储电影、剧集等各种资源以及进行全球分发。ML Model:机器学习的各种模型,用于推荐等等场景。Power BI:用于建立各种报表进行分析。
infrastructure 基础架构模块
通用基础架构
网飞作为流媒体领域的互联网巨头,技术水平非常高,开源很多自研的框架。我们结合上面的一些技术栈来讲讲:
AWS:这个云服务我就不赘述了CDN:将内容分发到更靠近用户的服务器节点,提高视频流的观看体验,包括降低延迟、增加稳定性、提高用户体验、以及节约带宽成本Atlas:一种用于管理维度时间序列数据的后端系统,可以处理来自各种来源的大量指标数据,例如服务的性能指标、用户行为数据等。网飞开源Eureka:服务注册与发现组件,实现微服务动态调度。网飞开源Jenkins:CI 工具(非网飞开源)Spinnaker:一个开源的持续交付平台,CD工具(非网飞开源)K8S / Titus:容器集群管理工具Chaos Monkey:混沌工程,随机终止生产环境中运行的虚拟机实例和容器 ,用来测试系统的弹性和容错能力。网飞开源Zuul:动态路由与服务网关,处理负载均衡和请求过滤。网飞开源
此外网飞还有很多的开源项目,感兴趣可以到网飞的github中查看:
B 端企业应用
同样的,网飞也是全球最大的电影制片厂之一,因此有很多支持电影制作的内部企业应用。这类应用通常是更传统的企业应用,QPS低,并发用户少,只需要单区域部署。 与流媒体应用不同,数据准确性非常关键,不能容忍失败(例如,保存数据必须成功)。这类应用的数据通常更适合存储在关系型数据库中(如 PostgreSQL、MySQL)。
很多公司的B端应用其实是单体式的,毕竟单体维护起来比微服务容易很多。但网飞的B端服务采用了和流媒体C端相同的基于 GraphQL 的架构。
ToB Application Architecture
同样通过 GraphQL 请求到达 Federated Gateway,Gateway 再将请求路由到对应的 DGS(Java/Spring Boot 微服务)。这些 DGS 可能连接到 PostgreSQL 等关系型数据库,各个DGS微服务之间通信同样使用 gRPC。
⚠️ 注意这里的一个细节,JDK版本是17/21+,我们知道很多公司的JDK版本还是停留在JDK8,网飞之前也是JDK8,在这几年才升级到高版本的JDK。这带来繁重的兼容工作外,还带来了巨大的性能提升,而篇幅受限,网飞架构的演进,Java的升级就放在下一篇文章中
参考
https://www.youtube.com/watch?v=XpunFFS-n8I&ab_channel=Java
https://blog.bytebytego.com/p/evolution-of-java-usage-at-netflix
https://netflixtechblog.com
https://netflixtechblog.com/how-netflix-content-engineering-makes-a-federated-graph-searchable-part-2-49348511c06c
页:
[1]