san*_*ain 5 database transactions jta xadisk
我正在构建一个 Web 应用程序,用户可以在其中创建报告,然后为创建的报告上传一些图像。当用户单击报告页面上的按钮时,这些图像将在浏览器中呈现。这些图像是保密的,只有授权用户才能访问它们。
我知道将图像存储在数据库、文件系统或亚马逊 S3 等服务中的优点和缺点。对于我的应用程序,我倾向于将图像保留在文件系统中并将图像的路径保留在数据库中。这意味着我必须处理分布式事务管理带来的问题。我需要一些关于如何处理这些问题的建议。
1-我相信正确的解决方案之一是使用 JTA 和 XADisk 等技术。我对这些技术不是很了解,但我相信两阶段提交是实现自动化的方式。我使用MySQL作为数据库,MySQL似乎支持2阶段提交。这种方法的问题是 XADisk 似乎不是一个活跃的项目,并且没有太多关于它的文档,而且事实上我对这种方法的来龙去脉不是很了解。我不确定我是否应该投资这种方法。
2-我相信我可以避免因违反应用程序的 ACID 属性而产生的一些问题。上传图像时,我可以首先将文件写入磁盘,如果此操作成功,我可以更新数据库中的路径。如果数据库事务失败,我可以从磁盘中删除文件。我知道这仍然不是无懈可击的;数据库事务后可能会出现电力短缺,或者磁盘可能会暂时无法响应等等...我知道还存在并发问题,例如,如果一个用户尝试修改上传的图像,而另一个用户尝试删除它同时,也会出现一些问题。我的应用程序中并发更新的机会仍然相对较低。
我相信,如果发生这种特殊情况,我可以忍受磁盘上的孤立文件或数据库上的孤立图像路径。如果文件路径存在于数据库中而不是文件系统中,我可以在报告页面上向用户显示通知,他可能会尝试重新上传图像。文件系统中的孤立文件不会有太大问题,我可能会不时运行一个进程来检测此类文件。尽管如此,我对这种方法还是不太满意。
3-最后一个选项可能是根本不在数据库中存储文件路径。我可以构建文件系统,以便可以推断代码中的文件路径并立即加载所有图像。例如,我可以为每个报告创建一个名称为报告 ID 的文件夹。当请求加载报告图像时,我可以立即加载图像,因为我知道报告 ID。这可能最终会在文件系统中产生大量文件夹,我不确定这样的设计是否可以接受。该方案中仍然会存在并发问题。
我希望得到一些关于我应该遵循哪种方法的建议。
我相信你正在努力做到超级正确,也许不需要那么多,但我前段时间也遇到过一些类似的情况,并探索了不同的可能性。我不喜欢与选项 1 一致的选项,但关于选项 2 和选项 3,我有不同的成功方法。
我们首先总结一下大家关心的问题:
以及不同的方法:
您几乎可以使用任何关系数据库来确保数据库中的事务,并且S3可以确保新对象和新对象上传的写后读一致性。如果您获得PUT一个对象并获得一个200 OK,那么它将是可读的。现在,如何将所有这些组合在一起?您需要跟踪该过程。我可以想出两种方法:
transaction:
相同的报告-图像关系表,带有一些额外的状态列。
如RabbitMQ、SQS、AMQ等
可以使用任何队列系统而不是数据库表来完成非常类似的方法。我不会提供太多细节,因为这更多地取决于您的实际基础设施,而只是总体思路。
在这两种情况下,并发问题都不容易管理,但可以管理(在第一种情况下依靠数据库锁,在第二种情况下依靠 FIFO 队列),但始终需要一些应用程序逻辑
在某种程度上,如果我们能够将其视为配置设计的适当约定,那么没有数据库的系统将是完全可以接受的。你必须处理三件事:
让我们从3开始:
一般来说,像一个文件夹这样的东西report id会太简单,并且可能难以维护,而且最终也太简单了。这会导致问题,因为如果我们有一个文件夹images,每个报告只有一个文件夹,而明天您的报告少于 200k,则该images文件夹将包含 200k 个元素,甚至ls会花费太多时间,对于任何尝试访问的编程语言来说都是如此。那会杀了你
你可以考虑一些更复杂的事情。Magento 1个人喜欢我十多年前学到的一种方法,从那时起我就经常使用:使用遵循第一个外部规则的文件夹结构,但使用由文件名本身扩展的派生规则进行扩展。
myproduct.jpg/media/catalog/product/media/catalog/product/m/y/p/myproduct.jpg这将我们带到下一部分:
我之前实现过类似的系统,相当成功。它使我能够轻松保存文件并轻松检索它们,位置完全动态。这里的部分是:
逻辑很简单。命名空间让我知道文件将保存在哪里。例如,命名空间可以是companyname/reports/images.
假设开发一个用于读写的微服务:
为了保存文件,它接收:
它会做:
然后,为了阅读,客户端将使用也使用约定的 URL。例如你可以有类似的东西
https://myservice.com/{NAMESPACE}/{entity_id}
根据逻辑,微服务将知道在存储中的何处找到该图像并返回图像。
如果每个报告有多个图像,您可以执行不同的操作,例如: - 您可能希望在路径中包含第三个 slug,例如https://myservice.com/{NAMESPACE}/{entity_id}/1 https://myservice.com/{NAMESPACE}/{entity_id}/2等等... - 如果用于内部应用程序使用,您可以一个端点返回所有符合条件的图像的列表,假设https://myservice.com/{NAMESPACE}/{entity_id}返回一个包含所有图像 url 的数组
我如何实现这一点是使用非常简单的 yml 配置来定义逻辑,以及读取该配置的非常简单的代码。这让我有很大的灵活性。例如,如果报告属于不同公司或者是不同的报告类型,则将报告保存在完全不同的路径或服务器或 s3 存储桶中