【发布时间】:2016-04-10 12:36:34
【问题描述】:
我正在开发一个文件系统,它使用 fuse 库和 jnr-fuse (https://github.com/SerCeMan/jnr-fuse) 作为 java 绑定来封装对 Amazon S3 存储桶的访问。
我有一个正在运行的第一个版本,目前正在做一些代码清理和重构工作,试图将所有内容放入适当的多层架构中。
到目前为止,我大致有以下几点:
- 前端:这是来自 jnr-fuse 的 FuseFileSystem 接口的实际实现。它与 jnr (native) 类型有一些依赖关系,并且方法是 fuse 的 c 函数的 java 等价物。
- 服务层:一个接口具有来自前端层的所有文件系统方法的“非本地依赖”版本,但不依赖于 jnr 或 fuse。这个想法是,这也可以在其他上下文中使用(例如,作为 S3 的 java.nio.FileSystem-API 实现的核心组件或有人需要 API 使 S3 在“文件系统”中可访问的任何其他场景-ish” 时尚,但不想通过 fuse 做到这一点,因此不想要所有 jnr 依赖项)
我目前苦苦挣扎的是持久层:由于与 S3 的所有通信实际上都是通过 http 完成的,我正在做一些相当数量的缓存以减少流量并提高性能。 问题是缓存最适合的地方..
显然,实际的 DAO 不应该受到任何类型的缓存/锁定逻辑的污染——它们应该只处理对数据的实际访问(即对 S3 进行 http 调用)。 另一方面,服务层也不应该真正关心缓存(以防持久层及其缓存需求发生变化),因此我正在考虑执行以下操作之一:
- 使用“双重”持久层:每个 DAO 实现两次:一个版本拥有缓存并从缓存中提供数据。如果一个对象不在缓存中,我们将委托给第二个 DAO,后者实际获取该对象(然后将其添加到缓存中)
- 引入一个单独的“缓存”层,其接口与处理所有缓存要求并在必要时委托给持久层的实际持久层略有不同。
从服务层的角度来看,版本 1 会更干净 - 使用缓存和不使用缓存之间没有任何区别,因为对持久层的所有调用都将针对同一个接口。另一方面,它还将所有关于文件状态或“生命周期”的逻辑(打开 -> 读/写 -> 关闭)传输到持久层。 版本 2 将在“缓存”层内管理文件的生命周期,我认为这将使代码新手更容易理解整个事情。另一方面,它还假设总是会有一个缓存层(这可能是真的)。
从设计的角度来看,上述方法是否还有其他优点和缺点,或者是否有任何模式可以解决此类问题?
现在我宁愿选择选项 2,但听到一些意见真的很有趣。
【问题讨论】:
标签: caching architecture filesystems