高效的可扩展序列生成器实现

时间:2012-08-19 16:06:10

标签: java memcached redis sequence-generators

问题:
我需要实现多个共享序列生成器,将由50-100个Tomcat服务器使用。每个序列生成器应从1开始,并在每个请求后递增1。 序列生成器实现应具有原子增量命令。 Java客户端应该可用。

规模:
主动使用多达50000个序列生成器,对于每个序列生成器,我们期望在5-10秒内有一个增量请求。 每秒最多20000个请求
50-100个Java客户端(Tomcat服务器)。在这些服务器之间共享对序列生成器的访问。重要提示:只有2个客户端使用相同的序列生成器 50-100次 - 每个序列发生器的平均使用次数 24小时TTL - 发电机在创建后24小时内最多应该清洁 - 因此实际上可以有超过50000个序列发生器,但预计最多只能有50000个同时主动接收请求。

性能:
< 1ms优选的平均响应时间。平均超过2毫秒绝对不够好。

我们排除了Oracle的Sequence对象 我们目前正在考虑Redis和Memcached 两者都很快。

建议采用什么/足够好?
还有其他更好的技术用于此目的吗?

另一个重要问题:
哪个有更好的性能,用于incr,Redis或Memcached?

由于

2 个答案:

答案 0 :(得分:4)

Redis应该让你轻松做到这一点。

  1. 为每个序列生成器创建一个键
  2. 使用INCR命令获取下一个序列号
  3. 如果返回的数字为1,则表示该密钥先前不存在。在这种情况下,您还应该发出PEXPIRE命令以在24小时后使密钥到期
  4. 为了进一步减少延迟,您可以做几件事 -

    1. 仅为序列生成器维护Redis服务器。换句话说,请勿在此服务器上存储任何其他数据。
    2. 不要使用AOF;而是使用RDB持久性。 AOF会将每个INCR命令附加到日志文件中,另一方面RDB将只存储每个序列的当前值。
    3. 您应该阅读diagnose latency problems以及redis persistence上的页面。

      此外,expire命令必须在24小时内最多发出一次,这需要两次往返redis。如果要避免这种情况,可以创建lua脚本。 rate limit lua script是一个很好的起点。

答案 1 :(得分:2)

我有以下建议:

天真的方法是有问题的,因为它涉及保持当前序列值的记录上非常细粒度的锁定。有这么多客户 - 它会造成无法忍受的争用。

我的建议是允许客户端对序列的范围进行预留。 因此,客户第一次订购范围,例如从1到1000。 该订单的处理是同步的。因此,如果另一个同时要求范围 - 它应该阻止并稍后接收范围1001到2000.

每个客户端获取一个不相交的序列池并从中提取值。一旦池耗尽,它就会向db询问另一个范围。如上所述,这涉及锁定。

问题是你可以微调范围的大小来权衡锁争用和资源利用(保证范围不能保证完全使用 - 客户可能会认为它不再需要任何序列或者它可能会崩溃共)。