跨多个线程/节点的会话管理

时间:2013-10-25 20:13:57

标签: java session backend couchbase enterprise

我们遇到了很多单独的线程/节点之间在会话中共享数据的问题。

场景如下所示: 有一些全局值的值类型为String,例如123ABC-1299AA。 用户向应用程序发送命令时需要取一个此值。不能有两个会话使用相同的值连接。

在环境中,我们有4台服务器,有50个线程在等待请求。

现状: 我们存储在Oracle DataBase映射值 - 会话中。使用UNIQUE值约束。当我们收到请求时,我们查询所有值的表,并迭代池,省略使用的值,找到一个空闲。如果在迭代时另一个线程放置了新值,我们将获得Unique约束,并尝试另一个。 DataBase也设计了一些持久性数据,这种映射之王不是持久性数据。

问题: Oracle不会处理一个具有大量读/写操作的小表。行锁定争用,重做日志问题等。除了我们在数据库中进行一些维护之外,我们正在观察超时,因为db的性能正在下降。

要求:

  • 会话的一个值,没有重复。
  • 响应时间短,不到100毫秒。
  • 所有应用程序节点上的数据一致性。
  • 在某种失败期间没有丢失映射。
  • 解决方案应处理高达100 TPS的流量。

你建议在这种情况下使用什么?

目前我们正在评估CouchBase的会话管理,但它有很多错误,并且故障转移效果很差(最多可能需要10分钟)。

2 个答案:

答案 0 :(得分:1)

我认为你不仅需要一个很好的数据库选择,还需要一些应用程序重组。我假设您使用的是集中式Oracle数据库,并且您的4个服务器中的每个服务器都写入同一个数据库。我还假设您正在进行客户端负载平衡,即您的客户端随机选择一个应用程序服务器来发送请求。

以下是我对此的一些看法:

- 为什么不将数据库分成n个分片(在你的情况下n = 4)。并且让每个应用服务器在新请求到来时随时查看自己的分片。想法是你想避免任何形式的争论。这里有一个最糟糕的情况。如果您最终遇到所有请求都来到其中一个应用服务器且该应用服务器的分片现已满,而其他插槽的分片中有空插槽,那该怎么办?如果您的客户随机选择一个应用服务器,您将没事。但是你仍然想要处理最糟糕的情况。因此,我的解决方案是:如果应用服务器意识到其分片已满,它将随机选择另一个应用服务器的分片,并将查询该分片为空槽。因此请注意,您最终会遇到两个应用服务器可能正在读/写相同表行的情况。但是这种情况发生的可能性会降低几个数量级,并且您的架构更加稳定。

但我们可以采取更多措施来处理2个app服务器可能正在读取/写入同一个分片的情况,因为其中一个应用服务器的分片已满。以下是一些想法: - Check-Then-Act在任何一种状态共享系统中始终是一个问题。因此,如果两个应用服务器正在查看相同的分片以获得空插槽,则它们将参与竞争(竞争条件)。在这种情况下我要做的是以这样的方式编写我的查询:如果当前值不同于我读取的值,那么我的应用服务器逻辑将再次进行搜索。如果当前值与我读取的值相同,则将插槽标记为NON-Empty。请注意,您需要将此作为同一事务执行,以便成为原子事务。它需要像Compare-And-Swap(CAS)。无论您使用SQL或NoSQL的数据库,您都必须在应用程序中编写逻辑,以便在遇到竞争条件时处理Check-Then-Act方案

我也认为Oracle不是一个很好的选择。首先它的价格昂贵,其次看起来你所需要的只是键值存储,所以在我看来,oracle是一种矫枉过正。此外,如果您有一个Oracle数据库,那么您只有一个故障点。

总的来说,群集(或分片)键值存储是一个很好的方法。在我看来,Couchbase并不是一个糟糕的选择。我已将它用于大规模会话管理。在我们的例子中,我们使用Moxi进行映射(对于我们来说是对于couchbase节点)。在我们的案例中,如果基础节点发生故障,Moxi花了一些时间(约2-5分钟)才意识到该节点已经关闭并选择了一个新的主基座副本。但是,如果您的应用程序更敏感,则可以在不使用Moxi的情况下使用Couchbase群集,并将映射请求的逻辑保留在应用程序中的couchbase节点。

但在您当前的情况下,如果您的Oracle数据库出现故障会怎样?我相信你的停机时间超过3-5分钟。我们的故障转移时间也是2-5分钟,因为我们有90多个couchbase节点。在您的情况下,您可能只需要几个(4-5),故障转移将在几秒钟内完成。

我会在你的情况下做的另一件事是我希望应用程序提前预留一些插槽,以便我的读写速度变快。因此,当应用程序保留了插槽时,这些节点将被标记为"保留"。如果该应用程序服务器发生故障,将释放其所有保留节点。或者您可以像这样编写查询

如果会话=="保留"和app_server.health!=" ACTIVE"然后节点被认为是免费的。

因此,仅仅在数据库中编写app_server.health = INACTIVE即可自动释放所有标记的节点。我希望我传达了这个想法

数据基础架构扩展是一个有趣的问题,也是我喜欢的。如果您有任何疑问,请告诉我,我将很乐意为您提供帮助。

我的主要建议是:

- 您是否可以采用一种方法来为每个用户会话使用GUID,而不是为每个用户分配预先计算的会话ID(或值)?

- 想一下分片。分片并不意味着采用集群方法。您可以在单个节点中进行分片,以避免数据库表之间发生争用。

- 评估NOSQL供您使用。 Couchbase(文档存储)是不错的选择,我用它来大规模存储用户会话。如果你想购买免费的开源替代品,Riak,Redis也很好。 Redis不会提出内置集群。但很可能你不需要它。 Redis是超级上电,读写速度非常快。 Twitter使用Redis来保存所有用户的推文。

- 最终你必须在代码中处理竞争条件。因此,避免竞争条件,但准备好在它们发生时处理它们

- 如果您只有一个Oracle数据库,则您已经有单点故障,并且您的故障转移时间仍然是多分钟(或几小时)。因此,不要害怕冒险进入像Couchbase,Voldemort等集群键值存储。对于4-5个音符的集群,您的故障转移将非常快(几秒钟)

答案 1 :(得分:0)

它是3个节点的集群,故障转移到第二个集群。 Oracle是首选,因为它具有可靠性和数据一致性。

在数据库之间共享数据是可选的,但是当一个实例由于某种原因而关闭时会出现问题。其他人将首先使用他们的部件,然后他们会尝试使用第4部分。这是问题,因为这个实例每次都需要检查资源。所以获得价值会慢得多。我们的目标是在不到0.5秒内获得价值。我们有故障转移所以当一个节点发生故障时,没有问题,因为交换机需要几秒钟。问题是当实例挂起(节点接受查询而不处理),或者当数据库互连速度很慢时,一个节点会锁定某些行,而另一个节点也会尝试锁定(原始锁争用)。

关于问题: - 我们需要为会话分配唯一​​值;维护所有这些值在代码中很难,但是可能

- 我们的治理流程不会就此,安全性,故障转移等达成一致。

- 我现在正在评估CouchBase,现在看起来还不错,但我们遇到了故障转移问题,切换到另一个节点可能需要几分钟,而且还不能保证故障节点会将数据刷新到第二个。我会读到其他的。

- 使用Oracle,我们对另一个群集/节点的故障转移对我们来说是透明的。最糟糕的情况是节点挂起,通常是因为一些oracle错误。然后,当50-80%的流量出现故障时,我们会有10分钟的时间。

感谢您的回复,我将深入评估CB并阅读其他解决方案。