从零打造 WhatsApp

简介: 从零打造 WhatsApp

WhatsApp 是全球用户最多的 IM 系统之一,以很小的资源消耗支撑了超大规模的消息通信,通过思考 WhatsApp 的架构选择,可以帮助我们了解怎样打造一个简单高效的消息系统。原文:WhatsApp System Architecture[1]


今天我们要设计一个类似 WhatsApp 的即时通讯服务。


image.png

Alexander Shatov@Unsplash


WhatsApp 是全世界大部分人几乎每天都在使用的应用程序,帮助我们以友好便捷的方式联系世界各地的朋友。常用的聊天系统一般分为两种类型,一种永久存储所有的信息,典型的是 Facebook Messenger,另一种只在消息无法直接送达的时候存储信息,一旦消息发送成功并收到确认,就会从系统中删除,典型的是 WhatsApp。


功能性需求


  1. 支持一对一的聊天
  2. 支持离线时发送消息
  3. 支持向包括离线用户在内的其他用户发送消息
  4. 支持聊天群组
  5. 支持最多 256 名参与者的 WhatsApp 群组
  6. 支持视频聊天
  7. 支持群组视频聊天
  8. 支持语音消息
  9. 支持图片、视频、文件分享
  10. 支持加密消息
  11. 视频最大 16MB,时长 90 秒到 3 分钟
  12. 支持已读回执
  13. 用户最后上线时间(基于不同的场景)
  14. 已发送、已送达、已阅读状态显式
  15. 分享文件大小不超过 100MB
  16. 支持播放 youtube、音频和视频
  17. 支持视频格式:MP4、3GP、MKV、AVI、MOV
  18. 一旦文件、视频、音频和图像超过大小限制,将显示状态通知
  19. 支持分享文件、视频、音频和图像到其他应用程序
  20. 支持在群组聊天中回复特定的消息
  21. 允许转发任何消息
  22. 允许拷贝消息
  23. 允许保存消息
  24. 允许将消息存档
  25. 允许我们私下回复消息
  26. 允许只发送和查看视频、图像一次,阅后即焚
  27. 允许删除消息
  28. 对于特定消息,支持向 WhatsApp 团队报告
  29. 支持通过 WhatsApp 拍照
  30. 支持当录音功能设置为全开后进行录音
  31. 支持访问手机联系人列表
  32. 支持共享位置(共享实时位置或共享当前位置)
  33. 支持通过 Facebook Messenger、邮件、微信、Telegram 等分享视频和文件
  34. 允许编辑、上传、删除用户配置文件
  35. 允许添加个人简介
  36. 允许绑定其他设备
  37. 允许更新状态
  38. 对于不同的场景,允许定制设置


非功能性需求


  1. 超低时延
  2. 永远可用
  3. 没有延时
  4. 高可扩展性
  5. 一致性(在其他设备上显示的内容,将与其他设备同步)

系统架构组件


image.png


1. 用户数据库

  • 存储用户状态、头像、ID、联系方式等配置文件信息
  • 个人头像存储在 AWS S3[2]上,每个头像都有各自的链接

image.png

2. 用户服务(API)


  • 具有多个端点,可帮助检索有关用户的详细信息,支持获取、检索用户配置信息


3. 映射数据库


  • 在我们深入了解之前,需要先了解一下一般通信体系结构的概念。当两个客户端(A 和 B)想要互相通信和发送消息时,必须知道对方的地址(IP、MAC 或任何特定的唯一标识),并通过网络(当前主要是互联网)交换消息,通常客户端会创建双向连接进行通信。这一系统会不断进化,最后可能会像下面的图片一样,其中包括了服务器、客户机、负载均衡器和数据库。


image.png


  • 我们不使用 HTTP 协议,因为每个用户都需要向服务器发送请求,一旦客户端从服务器接收到响应,HTTP 连接就会关闭,这意味着每个消息都需要等待服务器和客户端之间完成完整的事务。但是,每次都创建 HTTP 连接非常浪费时间和资源,因此我们选择使用 WebSocket 协议,保证连接不会被立即关闭。WebSocket 处理程序 WSH1 将建立用户连接,是一个轻量级服务器,与所有活动用户保持连接。
  • 每台机器有大约 65K 个开放端口,即使我们最终使用多达 5K 个端口用于内部使用以及与系统中的其他服务通信,仍然有多达 60K 的端口可以用于与用户连接。一个 WebSocket 处理程序将连接到一个 WebSocket 管理器,该管理器维护了一个哪些 WebSocket 处理程序连接到哪些用户的信息存储库。管理器使用 Redis 作为存储,包含两种类型的信息:哪个用户连接到哪个 WebSocket 处理程序,某个 WebSocket 处理程序上连接的所有用户。当用户和 WebSocket 处理程序的连接中断,可以将他们连接到另一个处理程序,而相关信息也将被更新到 Redis。
  • 消息服务:系统中所有消息的存储库。API 通过各种过滤器获取消息,如用户 id、消息 id、发送状态等。新老用户每天都在聊天,因此数据不断增长,当前采用 Cassandra 用于消息服务。WebSocket 处理程序会并行与 WebSocket 管理器、消息服务进行通信。


image.pngimage.png



  • 然后我们可以推导出一些场景。例如,发送方连接到服务器,但接收者没有上线,消息存储在数据库中,当接收方连接到服务器时,可以从数据库中获取消息。当发送方未连接到服务器时,消息将保存在设备存储中(可能是 SQLite 或基于平台的任何东西),当发送方联机时,消息将从本地存储中获取并发送到服务器。当两个客户端都连接到服务器时,发送方发送消息,服务器将消息转发给接收方,数据库或设备本地存储中不会保存消息。
  • 映射数据库——聊天服务器为发送方(用户 A)创建一个新进程(或线程),如果接收方(用户 B)在线,则同样如此。服务器找到接收方名称,从数据库中取出数据,并找出用户 B 的进程 id(pid),以便将消息发送给用户 B。如果用户 B 想发送消息到用户 A,服务器同样通过映射数据库中用户 A 的名字找到 pid,并将消息发送到该 pid。无论何时当有用户与系统建立连接,都会创建一个新的进程,所有细节都存储在映射数据库中。


image.png

在实际应用中,结构应该类似下图:


image.png


每个聊天服务器都包含一个队列,队列可以处理过多的消息负载,并且在向不同用户发送任何消息时不会失败。


4. 群组服务


  • 对于新创建的群组,也会有一个新的 groupId,这个 groupId 将映射到组中的所有用户。发送消息的时候,聊天服务将找到所有类型的接收方,可能是群组或单个用户,如果是群组,聊天服务将通过群组服务查询到 groupId 相同的所有用户,将消息发送给所有这些用户。


image.png


  • WebSocket 处理程序不能绑定群组,只能绑定活动用户。因此,当一个发送者想要向一个群组发送消息时,发送者的 WebSocket 处理程序将与消息服务通信,将消息存储在 Cassandra 中。然后消息服务与 Kafka 通信,将这些消息保存在 Kafka 中,并通过一条指令发送给群组。Kafka 会和群组消息处理器交互,发送所有的群组消息,这就是群组服务的机制。群组消息处理程序将与群组服务通信,找出群组列表中的所有用户,然后通过 WebSocket 处理程序将消息单独传递给所有用户。
  • 群组服务维护所有与群组相关的信息,比如哪个用户属于哪个组、用户 id、组 id、创建组的时间、添加每个用户的时间、状态、群组图标等。这些数据也将存储在 MySQL 数据库中,该数据库在不同的地理位置有多个从库服务器,以减少延迟。对于访问频繁的群组,将理由缓存优化访问。


5. 最后上线时间服务(Last Seen Service)


  • 最后上线时间服务使用最后上线数据库,以便存储最后上线信息。它只保留最后一次上线的时间细节,最新的信息总是替换旧的信息。当用户打开 WhatsApp 并向聊天服务器发送任何与用户相关的请求时,聊天服务器可以调用该服务来更新时间。


image.png


6. 消息存储服务器以及临时消息存储数据库


  • 当接收方离线时,消息需要加密保存在服务器的数据库中。一旦接收方上线,所有的消息都可以被传递


7. 多媒体消息


聊天服务获取消息并找出消息的类型,一旦聊天服务检测到消息类型是多媒体格式后,就将其存储在 AWS S3 这样的对象存储服务中。这些多媒体文件的存储链接将被存储在 SQL 或 NoSQL 数据库中,并和用户详细信息相映射,可以使用 HTTP 协议来传递这些消息。


image.png


  • 通过 WhatsApp 发送的图片、文件和视频将在设备端进行压缩和加密,加密后的内容将发送到接收端,内容将在设备端和接收端进行解密。
  • 如果一个用户向另一个用户发送图片,该用户将把图片上传到服务器并获得图片 id,然后图片 id 将被发送给另一个用户,另一个用户可以从服务器搜索和下载图片。或者另一种方案是在设备端将图片压缩,并通过负载均衡器发送到资产服务(Asset Service),将图片存储在 AWS S3 中。一旦图片存储到 S3 中,资产服务将返回图片 id,用户可以通过 WebSocket 处理程序将图片 id 发送给另一个用户。

WhatsApp 前端


  • Android:Java
  • iOS:Swift
  • Windows Phone:C#
  • Web app:JavaScript/HTML/CSS
  • Mac 桌面:Swift/Objective-C
  • PC 桌面:C/C#/Java


WhatsApp 后端


  • Erlang 是主要的编程语言
  • FreeBSD 是操作系统
  • Ejabberd 是 XMPP 应用服务器
  • BEAM 是 Erlang 虚拟机
  • Mnesia 是 Erlang 数据库
  • YAWS 是多媒体 web 服务器

系统概要设计


image.png


参考资料


References:

[1] WhatsApp System Architecture: https://medium.com/interviewnoodle/whatsapp-system-architecture-8df0250d572f

[2] AWS S3: https://aws.amazon.com/s3/

目录
相关文章
|
存储 Windows 数据安全/隐私保护
将FTP映射至Windows
在经常使用ftp传输文件的环境中,每次上传和下载文件都需要重新连接然后登录是非常繁琐的一件事情。我们可以将FTP空间映射到本地磁盘空间,免去输入地址以及账号、密码。方便我们日常中文件的上传和下载。 1. 双机桌面上的我的电脑,然后点击映射网络驱动器 2. 选择映射网络驱动器 3. 选择 连接到可用于存储文档和图片的网站 4. 下一步 5. 下一步 5. 根据示例,填写FTP地址 6. 输入用户名。
3868 0
|
8月前
|
监控 Java API
1K star!这个开源项目让短信集成简单到离谱,开发效率直接翻倍!
SMS4J 是一款由国内技术团队打造的短信聚合框架,专为解决多短信服务商接入难题而生。它就像短信界的"瑞士军刀",目前已整合21家主流短信服务商,从阿里云、腾讯云到中国移动云MAS,开发者只需通过简单配置即可实现多平台无缝切换。
529 4
|
5月前
|
安全 Linux 网络安全
ssh-server配置文件参数PermitRootLogin介绍
**PermitRootLogin** 是 SSH 服务(sshd)配置文件 /etc/ssh/sshd_config 中的一个参数,用于控制是否允许通过 SSH 直接以 root 用户身份 登录到服务器。这个设置是为了增强系统的安全性,特别是在远程访问和管理服务器时。
498 0
|
存储 缓存 监控
Java中的线程池深度解析####
本文深入探讨了Java并发编程中的核心组件——线程池,从其基本概念、工作原理、核心参数解析到应用场景与最佳实践,全方位剖析了线程池在提升应用性能、资源管理和任务调度方面的重要作用。通过实例演示和性能对比,揭示合理配置线程池对于构建高效Java应用的关键意义。 ####
|
存储 安全 数据库
阿里云最新域名注册和续费、企业邮箱、云虚拟主机收费标准与价格参考
域名注册和续费以及企业邮箱和云虚拟主机是很多用户上云第一步需要购买的产品,从2024年9月1日开始,全球域名又迎来了一波价格上调,目前阿里云的.com英文域名的注册价格由原来的78元涨价到了83元,续费价格也涨到了90元,不过企业新用户注册有1元购等活动。企业邮箱目前活动价540.00元/1年起,云虚拟主机独享基础增强版月付49元/1个月起,年付588元/1年起。本文为大家整理汇总了截止目前,阿里云域名注册和续费及转入收费标准、企业邮箱收费标准与活动价格、云虚拟主机最新收费标准,以供参考。
|
Arthas Prometheus 监控
JVM工作原理与实战(二十九):监控内存泄漏的工具
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了解决内存溢出的步骤、Top命令、VisualVM、Arthas、Prometheus + Grafana等内容。
969 0
|
NoSQL Redis
透视Redis集群:心跳检测如何维护高可用性
Redis心跳检测保障集群可靠性,通过PING命令检测主从连接状态,预防数据丢失。当连接异常时,自动触发主从切换。此外,心跳检测辅助实现`min-slaves-to-write`和`min-slaves-max-lag`策略,避免不安全写操作。还有重传机制,确保命令无丢失,维持数据一致性。合理配置心跳检测,能有效防止数据问题,提升Redis集群的高可用性。关注“软件求生”获取更多Redis知识!
848 10
透视Redis集群:心跳检测如何维护高可用性
|
JSON NoSQL MongoDB
MongoDB详解(五)——MongoDB数据库简单使用
MongoDB详解(五)——MongoDB数据库简单使用
766 1
|
机器学习/深度学习 并行计算 流计算
【GPU】GPU CUDA 编程的基本原理是什么?
【GPU】GPU CUDA 编程的基本原理是什么?
429 0
|
JavaScript
[Vue warn]: Unhandled error during execution of scheduler flush. This is likely a Vue internals bug.
[Vue warn]: Unhandled error during execution of scheduler flush. This is likely a Vue internals bug.
1786 0