【问题标题】:Session Management across multiple Thread/nodes跨多个线程/节点的会话管理
【发布时间】:2013-10-25 20:13:56
【问题描述】:

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

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

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

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

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

要求:

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

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

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

【问题讨论】:

  • 我不能凭经验说话,但我在 Riak 上看到了一些演示,它超级稳定,性能非常好:docs.basho.com/riak/1.4.0/cookbooks/use-cases/session-storage
  • Couchbase 经常用于这种用例。你能给我更多关于你看到的错误和故障转移的信息吗? (故障转移是即时的,根据您的配置可能需要一些时间,是系统发现节点关闭的事实)
  • 我们对CouchBase的问题是,当一个节点宕机时,不能保证切换后数据是一致的。目前我们有 2 个集群,每个集群有两个节点。在集群中切换很快,但在集群之间切换可能需要几分钟。而且还会丢失数据。关于我们写给 Couchbase 的错误,他们修复了它们。或者如果它很重要,我们会自行修复它并将补丁发送给 CB。主要是我们可以看到java-client的bug。

标签: java session backend couchbase enterprise


【解决方案1】:

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

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

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

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

我也认为 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 个注释的集群,您的故障转移将非常快(几秒钟内)

【讨论】:

    【解决方案2】:

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

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

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-21
      • 1970-01-01
      • 2016-12-28
      相关资源
      最近更新 更多