具有分布式无服务器应用,基于AWS Aurora serverless MySQL 5.6和多个Lambda函数。一些Lambdas表示写线程,另一些表示读线程。为了表示最重要的细节,让我们假设只有一个具有以下结构的表:
id: bigint primary key autoincrement
key1: varchar(700)
key2: bigint
content: blob
unique(key1, key2)写线程以以下方式执行插入:每个写线程生成一个带有key1+key2+content的条目,其中key1+key2对是唯一的,id是通过自动增量自动生成的。如果key1+key2有重复值,一些写线程可能会因为DUPLICATE KEY ERROR而失败,但这无关紧要。
还有一些读线程,它们是轮询表,并试图处理新插入的条目。读取线程的目标是检索所有新条目并以某种方式处理它们。读取线程的数量是不受控制的,它们不会相互通信,也不会在上面的表中写入任何内容,但可以在自定义的表中写入一些状态。
首先,轮询似乎非常简单-它足以读取进程来存储已处理的最后一个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将永远丢失。
问:有没有办法解决上面的问题,而不是所有集群上的硬锁表,以某种锁较少的方式或类似的方式?
发布于 2019-07-18 17:09:56
这里的问题是,每个lambda (线程)中的局部状态并不反映所述表的全局状态。
作为第一次调用,我会尝试在读取具有最新ID的条目之前,始终查阅表格what‘s latest ID。
看看MySQL中的内置函数LAST_INSERT_ID()。
注意事项
...最近生成的ID以每个连接为单位保存在服务器中
您的lambda可以在处理程序函数/方法之前创建连接,这将使它们的寿命更长(这是一个已知的技巧,但在这里它不是防弹的),但我认为新的同时执行的lambda函数将被赋予一个新的连接,在这种情况下,上面的解决方案将会崩溃。
幸运的是,接下来您必须做的是将所有写操作和所有读操作包装在事务中,以便在同时对同一个表进行读写操作时进行额外的协调。
在你的探索中,你可能会遇到和SEERIALIZEABLE是最安全和性能最差的,但apparently AWS Aurora does not support it (我还没有验证过这一说法)。
HTH
https://stackoverflow.com/questions/57090226
复制相似问题