Max*_*Max 8 rest post distributed http idempotent
我一直在寻找一种方法来设计我的 API,使其具有幂等性,这意味着其中一些方法是为了使我的 POST 请求路由具有幂等性,我偶然发现了这篇文章。
(如果我理解的不对,请纠正我!)
其中对总体思路有很好的解释。但缺少的是他自己实施的一些例子。
有人问文章作者,他如何保证原子性?所以作者添加了一个代码示例。
本质上,在他的代码示例中有两种情况,
如果一切顺利的话流程:
Idempotency-key键和值,这是对客户端的响应如果代码内部出现问题,流程如下:
注意,打开的事务是针对某个DB的,我们称他为A。但是,它与他也使用的redis存储无关,这意味着事务的回滚只会影响DB A。
因此,它涵盖了代码内部发生某些事情导致无法完成交易的情况。
但是,如果运行代码的机器在已经执行完Set expire time to that key并且即将运行事务提交的状态下崩溃,会发生什么情况?
在这种情况下,密钥将在 Redis 存储中可用,但事务尚未提交。这将导致这样的情况:服务确定所需的更改已经发生,但事实并非如此,机器在完成之前就发生了故障。
我需要以这样的方式设计API:如果redis中的数据更改或键和值的设置失败,它们都会回滚。
这个问题的解决办法是什么?
如何保证在一个数据库中更改所需数据的原子性,同时在redis中设置密钥和所需响应,如果其中任何一个失败,则将它们都回滚?(包括机器在操作过程中崩溃的情况)
请在回答时添加代码示例!我使用与本文中相同的技术(nodejs、redis、mongo - 用于数据本身)
谢谢 :)
根据您在问题中共享的代码示例,您想要的行为是确保在将幂等键设置到 Redis 中表示此事务已经发生的时刻和事务发生的时刻之间,服务器上没有崩溃,事实上,持久化在你的数据库中。
\n\n但是,当将 Redis 和另一个数据库一起使用时,您会遇到两个独立的故障点,并且两个操作在不同时刻按顺序执行(即使它们同时异步执行,也不能保证服务器赢\xe2\x80\ x99t 在其中任何一个完成之前崩溃)。
\n\n相反,您可以做的是在事务中包含一条插入语句,该语句指向包含此请求的相关信息(包括幂等键)的表。由于 ACID 属性确保原子性,它保证事务上的所有语句都成功执行,或者都不执行,这意味着如果事务成功,您的幂等性密钥将在数据库中可用。
\n\n您仍然可以使用 Redis,因为它\xe2\x80\x99s 会提供比数据库更快的结果。
\n\n下面提供了一个代码示例,但最好考虑一下插入 Redis 和数据库之间的失败与您的业务之间的相关性(是否可以用其他策略来处理?)以避免过度设计。
\n\nasync function execute(idempotentKey) {\n try {\n // append to the query statement an insert into executions table.\n // this will be persisted with the transaction\n query = ```\n UPDATE firsttable SET ...;\n UPDATE secondtable SET ...;\n INSERT INTO executions (idempotent_key, success) VALUES (:idempotent_key, true);\n ```;\n\n const db = await dbConnection();\n await db.beginTransaction();\n await db.execute(query);\n\n // we\'re setting a key on redis with a value: "false".\n await redisClient.setAsync(idempotentKey, false, \'EX\', process.env.KEY_EXPIRE_TIME);\n\n /*\n if server crashes exactly here, idempotent key will be on redis with false as value.\n in this case, there are two possibilities: commit to database suceeded or not.\n if on next request redis provides a false value, query database to verify if transaction was executed.\n */\n\n await db.commit();\n\n // you can now set key value to true, meaning commit suceeded and you won\'t need to query database to verify that.\n await redis.setAsync(idempotentKey, true);\n } catch (err) {\n await db.rollback();\n throw err;\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
8956 次 |
| 最近记录: |