保持数据库的数据与水平比例同步
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)