一百万个棋盘:用技术实现 One Million Chessboards
作者创建了一个名为 [One Million Chessboards](https://eieio.games/blog/one-million-chessboards/) 的网站,提供一百万个棋盘供玩家同时游戏。所有棋盘共享一个状态,移动会立即影响所有人。
该项目在技术上具有挑战性,后端使用 Go 编写,棋盘数据存储在内存中。前端采用乐观更新,并使用依赖图处理冲突。服务器通过 WebSockets 传输数据,客户端分组接收更新。
发布后,网站表现良好,服务器负载低。玩家可以访问网站进行游戏。
eieio.games by nolen royalty
One Million Chessboards
一百万个任何人都可以玩的棋盘
2025年4月28日
我做了一个网站,叫做 One Million Chessboards。它上面有一百万个棋盘。
移动一个棋子会立即影响到所有人。没有回合限制。你可以在棋盘之间移动。
加载中... 移动一些棋子
What (是什么)
去年我做了一个叫做 One Million Checkboxes 的游戏。
那是一段非常有趣的时光!所以我决定再做一些类似的事情。
我在这上面投入了大量的精力,希望你喜欢。
How (如何实现)
这是我长期以来在技术上最具挑战性的项目。我计划等看看我的决策会如何发展后再写一份完整的技术文档,因为我觉得我很有可能需要做出很多改变。
但我会为你总结一些关键点:
- 与 One Million Checkboxes 不同,我为这次的项目设计了可扩展性。
- 这个游戏运行在单个服务器上(!)。
- 棋盘完全存储在内存中;它是一个包含 6400 万个
uint64
的二维数组。 - 后端使用 Go 语言编写。这是我的第一个 Go 项目。
- 我使用一个写入线程、大量的读取线程,并使用互斥锁来协调对棋盘的访问。
- 前端会立即乐观地应用你所做的所有移动。然后,它会建立一个你所做的移动的依赖关系图,如果服务器在你确认移动之前收到了冲突的更新,它就会撤销这些移动。
- 服务器通过 WebSockets 将使用 zstd 压缩的 protobuf 发送到客户端,用于传输状态快照(大约是客户端周围 100x100 的区域)、移动和捕获更新,以及移动的确认/拒绝。
- 客户端被分组到 50x50 的“区域”中,并且只接收当前区域相邻区域的移动。
- 客户端通过 GET 请求轮询全局数据(游戏统计数据、小地图等);数据在 Cloudflare 中以较低的 TTL 缓存,因此这比通过每个 WebSocket 发送数据便宜得多。
最后一部分——带有游戏玩家有时称之为“回滚”的乐观移动应用——大约有 1600 行代码,花费了我大约 7 天的全职工作时间编写。我不记得上次我如此努力地解决一个问题是什么时候了!
截至晚上 8 点,在发布 8 小时后,玩家已经进行了大约 130 万次移动,并且大部分时间里有大约 400 名并发用户。我的服务器上的负载可以忽略不计!
Can I play (我能玩吗)
是的!在这里玩。
我真的希望你喜欢这个。 更多更新即将到来 :)
感谢阅读!