您需要担心的不是后端系统细节,而是前端。在任何实际规模下,始终打开连接都是不切实际的。相反,您希望相反 - 能够尽可能快地从后端服务和关闭连接。
Websockets 是一项性感的技术,但同样,在现实世界中,代理存在问题,如果您正在开发应该在各种屏幕(台式机、平板电脑、移动设备)上工作的东西,它可能会成为您的担忧。即使是古老的长民意调查也可能无法通过防火墙和代理。
这是一个好消息:我认为
“继续投票以获取每个答案的赞成票数”
在这种情况下是一个完全好的解决方案。考虑以下:
- 您的用例不需要任何实时更新。稍后看到计数器更新几乎没有什么坏处
- 对于非常受欢迎的主题,无论如何您都想将多个赞成/反对票压缩为一个
- 大多数主题在几天/几周内根本看不到赞成/反对投票的流量,因此保持连接打开,等待永远不会发生的事件是一种浪费
- 大多数用户永远不会对刚来阅读某个主题的人投赞成票/反对票,因此您对主题统计数据的读/写比率将大大偏向于阅读
- 客户端之间的网络延迟差异很大,您会看到 100B http 响应的可怕传输速率,而这个缓慢的客户端正在逐字节获取他的响应,您的宝贵服务器连接更重要的是 - 后端服务器上的线程正忙
这是我要开始的:
- 在主页加载后,让浏览器定期轮询新的主题统计信息
- 保留您的 MySQL,保留计数器。每次有赞成/反对票时更新数据库
- 将 Memcached 作为直写缓存放在 DB 前面,即每次有向上/向下投票更新缓存时,然后更新 DB。将计数器的显式过期时间设置为 10-15 分钟。每次更新计数器时,过期时间都会自动延长。
- 将这些轮询 http 调用设计为可被 http 代理缓存,将 expire 和 ttl http 标头设置为 60 秒
- 在前端服务器前面放置一个反向代理(Varnish,nginx ),让这个代理缓存上述轮询调用。这些负责二级缓存并帮助更快地释放后端服务器线程,请参阅上面的网络延迟问题
- 设置您的反向代理组件以直接与 memcached 服务器对话,而无需调用后端服务器,是的,如果您可以同时使用 Varnish 和 nginx。
- 存储此类数据没有花哨的模式,它是
inc()/dec()
memcached 中的一个简单操作,请注意,从竞争条件的角度来看它是安全的。在 MySQL 中也是一个安全的原子操作UPDATE table SET field = field + 1 WHERE [...]
积极的多级缓存涵盖了您的read
路径:在 Memcached 和所有 http 缓存中,请注意这些 http 轮询请求也将被缓存在边缘。
为了照顾不受欢迎的话题的长尾 - 使此类响应的 http ttl 与受欢迎程度成反比。
当 http 缓存过期并且 memcached 也没有它时,读取请求只会很少到达前端服务器。如果这仍然是一个问题,请添加 memecached 服务器并全面增加 memcached 中的过期时间。
完成后,您就完成了所有reads
工作。根据规模的不同,您可能仍然存在的唯一问题是高writes
/低投票率高。这是您的单个 MySQL 实例可能开始显示一些滞后的地方。不要害怕 - 沿着老路继续分片您的实例,或仅为计数器添加 NoSQL 存储。
除非绝对必要或者你想找个借口玩它,否则不要使用任何消息传递系统。