Caching 软件体系结构-服务层和持久层之间的缓存

Caching 软件体系结构-服务层和持久层之间的缓存,caching,architecture,filesystems,Caching,Architecture,Filesystems,我正在开发一个文件系统,它使用fuse库和jnr fuse()作为java绑定来封装对AmazonS3 bucket的访问 我有一个第一个版本正在工作,目前正在做一些代码清理和重构工作,试图将所有内容都纳入一个适当的多层体系结构中 到目前为止,我大致有以下几点: 前端:这是JNRFUSE中FuseFileSystem接口的实际实现。它对jnr(本机)类型有一些依赖性,并且这些方法是fuse的c函数的java等价物 服务层:一个接口,它具有来自前端层的所有文件系统方法的“非本机依赖”版本,但不依

我正在开发一个文件系统,它使用fuse库和jnr fuse()作为java绑定来封装对AmazonS3 bucket的访问

我有一个第一个版本正在工作,目前正在做一些代码清理和重构工作,试图将所有内容都纳入一个适当的多层体系结构中

到目前为止,我大致有以下几点:

  • 前端:这是JNRFUSE中FuseFileSystem接口的实际实现。它对jnr(本机)类型有一些依赖性,并且这些方法是fuse的c函数的java等价物
  • 服务层:一个接口,它具有来自前端层的所有文件系统方法的“非本机依赖”版本,但不依赖于jnr或fuse。其想法是,这也可以用于其他上下文(例如,作为S3的java.nio.FileSystem-API实现的核心组件,或任何其他场景,其中有人需要API以“文件系统”的方式访问S3,但不希望通过fuse实现,因此不需要所有jnr依赖项)
我目前正在努力解决的是持久性层:因为与S3的所有通信实际上都是通过http完成的,所以我正在进行一些相当数量的缓存,以减少通信量并提高性能。 问题是缓存在哪里最适合

显然,实际的DAO不应该被任何类型的缓存/锁定逻辑所污染——它们应该只处理对数据的实际访问(即对S3进行http调用)。 另一方面,服务层也不应该真正关心缓存(如果持久层及其缓存需求发生变化),因此我考虑执行以下操作之一:

  • 使用“双重”持久层:每个DAO实现两次:一个版本保存缓存并从缓存中提供数据。如果一个对象不在缓存中,我们将委托给实际获取该对象的第二个DAO(然后将其添加到缓存中)
  • 引入一个单独的“缓存”层,其接口与实际的持久性层略有不同,后者处理所有缓存需求,并根据需要委托给持久性层
  • 从服务层的角度来看,版本1将是更干净的版本-使用缓存和不使用缓存之间没有任何区别,因为对持久性层的所有调用都将针对同一接口。另一方面,它也会将与文件状态或“生命周期”(打开->读/写->关闭)相关的所有逻辑传输到持久层。 版本2将在“缓存”层中管理文件的生命周期,我认为这将使代码新手更容易理解整个过程。另一方面,它还假设始终存在缓存层(这可能是真的)

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


    现在我更愿意选择选项2,但听到一些意见会非常有趣。

    为什么您反对在DAO中缓存?这一直是我最好的藏身之地。这是一个数据访问问题,因此进入数据访问层。为了方便起见,我多次使用各种AOP实现,但90%的时候,我在DAO内部实现缓存逻辑

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


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

    为什么您反对在DAO中缓存?这一直是我最好的藏身之地。这是一个数据访问问题,因此进入数据访问层。为了方便起见,我多次使用各种AOP实现,但90%的时候,我在DAO内部实现缓存逻辑

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


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

    由于编排的原因,我仍然有疑问:当一个文件被另一个进程读取时,它会打开,然后读取,然后在读取完成后关闭。在调用open时,文件已加载到缓存中。然而,对于一个“纯”DAO,“开放”操作并没有真正意义(除非它有一个缓存)——关闭某些东西也是如此,这就是我考虑解耦的原因。但是你是对的,数据访问层可能仍然是最合适的——我只需要弄清楚细节;)由于编排的原因,我仍然有疑问:当一个文件被另一个进程读取时,它会打开,然后读取,然后在读取完成后关闭。在调用open时,文件已加载到缓存中。然而,对于一个“纯”DAO,“开放”操作并没有真正意义(除非它有一个缓存)——关闭某些东西也是如此,这就是我考虑解耦的原因。但是你是对的,数据访问层可能仍然是最合适的——我只需要弄清楚细节;)