保持数据库的数据与水平比例同步

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了保持数据库的数据与水平比例同步相关的知识,希望对你有一定的参考价值。

让我们假设我们有一个微服务“A”。我们现在正在水平扩展它,这意味着我们有3个“A”实例在同一个数据库实例上工作(而schemea,通常假设3个“A”实例可能对同一个数据进行读写操作)。

现在我将用一些伪代码演示这个问题,我们在“A”中有以下更新功能:

Product p = getProdFromDb(); // for example selecting 
// from Postgresql db

p.updateInnerData(); // synch method that updates 
// something inside the p model that takes significant 
// amount of time
p.updateInDb(); //  for example update back in postgresql

这里的问题是,其他“A”实例可能会在我们更新它时更改产品p(不是在此函数中,而是在那里有更改“A”中的产品的其他功能)。我知道的一个解决方案是在数据库上使用锁(例如使用“Select ... for Update”),但它会在此函数中产生性能瓶颈。我希望看到更好的解决方案,解决这个问题,没有这个瓶颈,Java(或JS)中的真实例子将非常有帮助。

编辑:假设分区不是一个选项

答案

有两种锁定:悲观(你试图避免的那种)和乐观锁定。

在乐观锁定中,您不会保留任何锁定,而是尝试保存文档;如果文档已经同时修改(意味着它自我们加载后就被修改了),那么你重试整个过程(加载+变异+保存)。

一种方法是使version列在每次改变实体时增加。当您尝试持久化时,您希望具有version = version + 1的实体不存在。如果它已经存在,则表示发生了并发更新,并且您重试(加载+变异+保存)。

在伪代码中,算法是这样的:

function updateEntity(ID, load, mutate, create)

    do
    {
        entity, version = load(ID) or create entity
        entity = mutate entity
        updateRow(that matches the ID and version) and increment version
    }
    while (row has not changed and was not inserted)

我将为您提供一个用于MongoDB的php代码示例(希望它易于理解):

class OptimisticMongoDocumentUpdater
{

    public function addOrUpdate(Collection $collection, $id, callable $hidrator, callable $factory = null, callable $updater, callable $serializer)
    {
        /**
         * We try to add/update the entity in a concurrent safe manner
         * using optimistic locking: we always try to update the existing version;
         * if another concurrent write has finished before us in the mean time
         * then retry the *whole* updating process
         */

        do {
            $document = $collection->findOne([
                '_id' => new ObjectID($id),
            ]);

            if ($document) {
                $version = $document['version'];
                $entity = call_user_func($hidrator, $document);
            } else {
                if (!$factory) {
                    return;//do not create if factory does not exist
                }
                $entity = $factory();
                $version = 0;
            }

            $entity = $updater($entity);

            $serialized = $serializer($entity);

            unset($serialized['version']);

            try {
                $result = $collection->updateOne(
                    [
                        '_id'     => new ObjectID($id),
                        'version' => $version,
                    ],
                    [
                        '$set' => $serialized,
                        '$inc' => ['version' => 1],
                    ],
                    [
                        'upsert' => true,
                    ]
                );
            } catch (MongoDBDriverExceptionWriteException $writeException) {
                $result = $writeException->getWriteResult();
            }

        } while (0 == $result->getMatchedCount() && 0 == $result->getUpsertedCount());//no side effect? then concurrent update -> retry
    }
}
另一答案

在我的回答中,我假设你想要100%的可靠性。

如果是这种情况,您可以将表格划分为多个页面,其中每个页面将包含X行数。当您尝试更新表时,您将只锁定该页面,但随后会有更多的I / O.

此外,在您的数据库上,您可以对其进行配置,以便select命令甚至可以读取未提及的行,这将提高速度 - 对于SQL服务器,它是SELECT WITH (NOLOCK)

以上是关于保持数据库的数据与水平比例同步的主要内容,如果未能解决你的问题,请参考以下文章

AutoLayout - 使用水平约束保持图像的比例(Swift Xcode 6)

iOS:使用自动布局保持视图彼此按比例调整大小

如何使 C# 枚举与数据库中的表保持同步

使用 Logstash 和 JDBC 确保 Elasticsearch 与关系型数据库保持同步

旋转 iPhone 并保持图像的比例

根据宽度计算div的高度并保持比例[重复]