0

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

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

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

现状:我们存储在Oracle数据库中的映射值——会话。具有唯一值约束。当我们收到请求时,我们查询表中的所有值,并遍历池,省略使用的值,以找到一个空闲的值。如果另一个线程在我们迭代时输入了新值,我们会得到唯一约束,并尝试另一个。另外DataBase是为一些持久数据设计的,这个映射之王不是持久数据。

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

要求:

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

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

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

4

2 回答 2

1

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

所以这里是我对此的一些想法:

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

但是我们可以做更多的事情来处理两个应用服务器可能正在读取/写入同一个分片的情况,因为其中一个应用服务器的分片已满。以下是一些想法: -- Check-Then-Act 在任何类型的状态共享系统中始终是一个问题。因此,如果两个应用服务器正在为一个空槽寻找同一个分片,它们将竞争(竞争条件)。在这种情况下,我要做的是以这样一种方式编写我的查询:如果当前值与我读取的值不同,那么我的应用服务器逻辑将再次进行搜索。如果当前值与我读取的值相同,则将插槽标记为非空。请注意,您需要将其作为同一个事务执行,以便具有原子性。它需要类似于比较和交换( CAS )。不管你用的是 SQL 还是 NoSQL 的数据库,

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

所以总的来说,集群(或分片)键值存储是您采用的好方法。在我看来,Couchbase 不是一个糟糕的选择。我已将它用于大规模会话管理。在我们的例子中,我们使用 Moxi 到映射(对我们来说是到 couchbase 节点)。在我们的例子中,如果 couchbase 节点出现故障,Moxi 需要一些时间(约 2-5 分钟)才能意识到该节点已出现故障并选择一个新的主 couchbase 副本。但是如果你的应用比较敏感,你可以使用没有 Moxi 的 Couchbase 集群,并在你的应用中保留映射请求到 couchbase 节点的逻辑。

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

在你的情况下我会做的另一件事是我希望应用程序提前保留一些插槽,以便我的读写变得更快。因此,当应用程序保留插槽时,这些节点将被标记为“保留”。如果该应用程序服务器出现故障,它的所有保留节点都将被释放。或者你可以这样写你的查询

如果 session == "reserved" 和 app_server.health != "ACTIVE" 那么节点被认为是空闲的。

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

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

我的主要建议是:

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

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

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

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

-- 如果您只有一个 Oracle 数据库,那么您已经存在单点故障,并且您的故障转移时间无论如何都会是几分钟(或几小时)。因此,不要害怕冒险进入 Couchbase、Voldemort 等集群键值存储。对于 4-5 个注释的集群,您的故障转移将非常快(在几秒钟内)

于 2013-10-25T23:12:51.740 回答
0

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

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

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

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

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

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

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

于 2013-10-29T19:41:21.463 回答