实现动态更新upvote/downvote

aks*_*202 9 mysql architecture memcached voting-system

如何实现类似于quora的动态更新投票计数: - 每当用户提交一个答案时,它会自动反映每个正在查看该页面的人.

我正在寻找一个解决以下问题的答案:

  • 我们是否必须为每个答案继续轮询upvote计数,如果是,那么如何管理由于许多用户
    轮询upvotes 而引起的服务器负载.
  • 或者使用websockits /推送通知,这些可扩展性如何?
  • 如何在数据库/内存中存储upvote/downvote计数以支持这一点.它们如何控制读/写次数.我的后端数据库是mysql

我正在寻找的答案可能并不完全是quora如何做,但可能是如何使用可用的开源技术来完成.

Yur*_*uri 5

Websockets,Server Sent Events(我认为这就是'推送通知'的含义)和AJAX长轮询具有相同的缺点 - 它们使底层TCP连接保持打开状态很长时间.
所以问题是服务器可以处理多少个开放的TCP连接.基本上,它取决于其操作系统,文件描述符的数量(配置参数)和可用内存(每个打开的连接保留读/写缓冲区). 这里有更多内容.

我们曾经测试过在一台服务器上打开100万个websocket连接的可能性(带有16Gb RAM的Windows 7 x64,带有8Gb堆的JVM 1.7,使用Undertow beta来提供Web请求).令人惊讶的是,最困难的部分是在服务器上产生负载)
它设法保持1M.但是,服务器再次没有做一些有用的事情,只是收到请求,通过协议升级并保持这些连接打开.无论出于何种原因,也有一些失去的联系.我们没有调查.但在生产中,您还必须ping服务器并处理重新连接.

除此之外,Websockets在这里看起来有点过分,SSE仍未被广泛采用. 所以我会选择旧的AJAX轮询,但要尽可能优化它.
无处不在,易于实现和调整,不依赖于外部系统(我有几次不好的经验),优化的可能性.例如,您可以在单个浏览器中为所有打开的文章分组更新,或根据文章的受欢迎程度调整更新间隔.
毕竟你似乎不需要这里的实时通知.


Igo*_*kov 5

您不需要担心的不是后端系统细节,而是前端。在任何实际规模上,始终保持打开连接是不切实际的。相反,您想要相反的事情-能够尽可能快地服务和关闭来自后端的连接。

Websockets是一种性感的技术,但是,在现实世界中,代理服务器还是存在一些问题,如果您开发的东西可以在各种屏幕(台式机,平板电脑,移动设备)上使用,则可能会成为您的问题。即使是经过很长时间的长期民意调查也可能无法通过防火墙和代理进行工作。

这是个好消息:我认为

“保持轮询以获取每个答案的投票数”

在这种情况下是一个很好的解决方案。考虑以下:

  • 您的用例不需要任何实时更新。稍后再更新计数器几乎没有什么害处
  • 对于非常热门的主题,您还是想将多个上投票/下票压缩为一个
  • 大多数主题在几天/几周内都看不到上/下投票的流量,因此保持连接开放,等待永不发生的事件是浪费
  • 大多数用户将永远不会对刚刚读过一个主题的投票进行投票/否决,因此您对主题统计信息的读/写比率将大大偏向阅读
  • 客户端之间的网络延迟差异很大,您会看到100B http响应的可怕传输速率,而这个缓慢的客户端正在逐字节获取您宝贵的服务器连接的响应,更重要的是-后端服务器上的线程很忙

这是我要开始的:

  • 在加载主页后,让浏览器定期轮询新的主题统计信息
  • 保留您的MySQL,在那里保留计数器。每次上/下投票都会更新数据库
  • 将Memcached作为直写式高速缓存放在数据库的前面,即每次有上/下投票更新缓存时,然后更新数据库。将计数器的显式到期时间设置为10-15分钟。每次计数器更新时,过期时间会自动延长。
  • 将这些轮询的HTTP调用设计为可被HTTP代理缓存,并将expire和ttl http头设置为60秒
  • 在您的前端服务器前放置一个反向代理(Varnishnginx),让该代理对所说的轮询调用进行缓存。这些可以处理二级缓存,并有助于更快释放后端服务器线程,请参阅上面的网络等待时间
  • 设置您的反向代理组件以直接与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存储。

除非绝对必要,否则不要使用任何消息系统,或者您想找个借口使用它。