具有基于AWS Aurora无服务器MySQL 5.6和多个Lambda函数的分布式无服务器应用程序。一些Lambda代表编写线程,而其他Lambda则代表阅读线索。为了表示最重要的细节,让我们假设只有一个表具有以下结构:
id: bigint primary key autoincrement
key1: varchar(700)
key2: bigint
content: blob
unique(key1, key2)
写入线程按以下方式执行INSERT:每个写入线程都使用key1+key2+content
生成一个条目,其中key1+key2
对是唯一的,而id
是通过自动递增自动生成的。如果DUPLICATE KEY ERROR
具有重复值,则某些写入线程可能会因key1+key2
而失败,但这没关系,还可以。
还有一些读取线程,这些线程正在轮询表并尝试处理新插入的条目。读取线程的目的是检索所有新条目并以某种方式处理它们。读取线程的数量不受控制,它们彼此之间不通信,也不在上面的表中写入任何内容,但是可以在自定义表中写入某些状态。
首先,轮询似乎非常简单-足以读取过程以存储最后一个已处理的id
,然后从中继续轮询,例如SELECT * FROM table WHERE id > ${lastId}
。上面的方法在小负载下效果很好,但在高负载下却不能工作,原因很明显:由于此时群集尚未同步,因此有一些插入条目尚未出现在数据库中。
让我们看看从群集的角度来看发生了什么,如果它仅由两个服务器A和B组成的话。
1)服务器A接受带有条目插入并获得自动递增编号100500的写事务。
2)服务器B接受带有条目插入并获得自动递增编号100501的写事务。
3)服务器B提交写事务
4)服务器B接受读取的事务,并返回带有id > 100499
的条目,该条目仅为100501
的条目。
5)服务器A提交写事务。
6)读取线程仅接收100501
项,并将lastId
光标移动到100501
。条目100500
对于当前的读取线程将永远丢失。
问题:是否可以通过某种不了解锁的方式或类似的方式在所有群集上没有硬锁表的情况下解决上述问题?
答案 0 :(得分:2)
这里的问题是每个lambda(线程)中的局部状态不反映所述表的全局状态。
作为第一个电话,我将尝试在读取具有该ID的条目之前始终咨询表的最新ID。
看看MySQL中的内置函数LAST_INSERT_ID()
。
[...]最近生成的ID保留在服务器上的 每个连接
您的lambda可能会在 handler 函数/方法之前创建连接,这将使它们的寿命更长(这是一个已知的技巧,但此处不具备防弹功能),但是我认为同时执行lambda函数的新函数将被赋予新的连接,在这种情况下,上述解决方案将崩溃。
幸运的是,您要做的是将所有WRITES和所有READS包装在事务中,以便在同时读取和写入同一张表时进行额外的协调。
在您的任务中,您可能会遇到 transaction isolation levels 和 SEERIALIZEABLE 是最安全且性能最低的,但是{{3} }(我尚未验证该声明)。
HTH