我们的 API 是为支持一百万用户而开发的。由于我们在 4 个月内达到了 50 万大关,我们现在正在扩展它以支持我们计划在一年内达到的 1000 万用户。目标是现实的,因为我们现在将核心数据处理/聚合逻辑作为 SDK 发送到其他应用程序。
当前的 API 是 HTTP post,其中正文是 JSON。当新用户注册时,他会从设备上传大约 200KB 的数据。以前我们用来处理数据服务器端,但现在我们在设备本身上处理它。
此后,该应用程序每天将上传大约 2KB 的数据并下载大约相同的数据。对于拥有多个移动设备的用户来说,这个数字要多一些,但仅占总用户群的 1%。
现在我们的 API 服务器使用 Jetty+Jersey,平均有大约 200 个并发连接。它可以处理大约 500-1000 个并发连接(取决于请求的类型)。
每个 API 服务器(共 4 个)有 120 个数据库连接。我们的工作量是 80% 的写入和 20% 的读取,更新可以忽略不计。
现在 API 是同步的,我的意思是对于每个请求,我们存储/检索数据并将确认/数据发送回客户端。
一种扩展方法是扩展(垂直和/或水平)我们的 API 服务器并在 userId 上对数据库进行分片。完成数据库分片是因为我们估计每百万用户需要 1TB 的数据存储。我们还计划迁移到 SSD,但这需要一些时间,因为我们有自己的数据中心并且迁移正在进行中。
我预见的主要挑战是在 sdk 推出流行应用程序时处理新用户的激增。我正在考虑一些方法:
1)在写入请求期间,只需提取实体,推送到 KAFKA 并向客户端发送 ACK。消费者比提取实体从队列中持久化并分批插入它们。
2)使用不同的读写服务器。对于读取使用现有的同步架构。对于写请求公开一个由 Netty 支持的不同 URL,它将提取实体以持久化并将它们推送到内存队列,向客户端发送 ACK。异步传输到 kafka 队列,然后最终传输到数据库。
3) 对每个请求使用异步服务器 Quasar+Comsat 和轻量级线程,让客户端等待确认(也获取持久实体的自动增量 ID)。问题是数据库连接的数量是瓶颈,允许产生许多并发的轻量级线程可能并没有真正的帮助。
任何有关指出这些方法的优点/缺点/改进的帮助或对新方法的建议都会有很大帮助。即使我们从 10M 扩展到 100M,关于这些方法中的哪一种是正确的观点也会有所帮助。我们没有网络界面,所以所有的数据传输都是纯 json 的,在发展中国家,我们还必须支持 2G 设备和大量网络断开,所以也必须考虑到这一点。