【问题标题】:SW-Architecture - Caching between service- and persistence layerSW-Architecture - 服务层和持久层之间的缓存
【发布时间】: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 调用)。 另一方面,服务层也不应该真正关心缓存(以防持久层及其缓存需求发生变化),因此我正在考虑执行以下操作之一:

  1. 使用“双重”持久层:每个 DAO 实现两次:一个版本拥有缓存并从缓存中提供数据。如果一个对象不在缓存中,我们将委托给第二个 DAO,后者实际获取该对象(然后将其添加到缓存中)
  2. 引入一个单独的“缓存”层,其接口与处理所有缓存要求并在必要时委托给持久层的实际持久层略有不同。

从服务层的角度来看,版本 1 会更干净 - 使用缓存和不使用缓存之间没有任何区别,因为对持久层的所有调用都将针对同一个接口。另一方面,它还将所有关于文件状态或“生命周期”的逻辑(打开 -> 读/写 -> 关闭)传输到持久层。 版本 2 将在“缓存”层内管理文件的生命周期,我认为这将使代码新手更容易理解整个事情。另一方面,它还假设总是会有一个缓存层(这可能是真的)。​​

从设计的角度来看,上述方法是否还有其他优点和缺点,或者是否有任何模式可以解决此类问题?

现在我宁愿选择选项 2,但听到一些意见真的很有趣。

【问题讨论】:

    标签: caching architecture filesystems


    【解决方案1】:

    您为什么反对在 DAO 中进行缓存?这一直是我缓存的理想场所。这是一个数据访问问题,因此进入数据访问层。有几次,为了方便起见,我使用了各种 AOP 实现,但 90% 的时间,我在 DAO 中实现缓存逻辑。

    缓存本身并不存在于 DAO 中,它通常是它自己的接口,所以我可以在实现之间交换(内存中、磁盘上等)。

    在使用 Apache HTTP 客户端自己的内置缓存时,我也有一些运气。它允许您尊重 HTTP 缓存语义,或使用自定义逻辑覆盖它。

    【讨论】:

    • 由于编排,我仍然有疑问:当另一个进程读取文件时,它会打开,然后读取,然后在读取完成后关闭。在调用 open 的那一刻,文件已经加载到缓存中。然而,对于“纯”DAO,“打开”操作并没有真正意义(除非它有缓存)——关闭某些东西也是如此,这就是我考虑将其解耦的原因。但你是对的,数据访问层可能仍然是最合适的——我只需要弄清楚细节;)
    猜你喜欢
    • 2021-02-11
    • 2018-01-21
    • 1970-01-01
    • 2014-10-08
    • 1970-01-01
    • 2014-05-22
    • 2011-06-30
    • 1970-01-01
    • 2011-02-17
    相关资源
    最近更新 更多