我认为您不仅需要一个好的数据库选择,还需要一些应用程序重组。我假设您使用的是集中式 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 个注释的集群,您的故障转移将非常快(在几秒钟内)