Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/36.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js 与GraphQL数据加载器一起实现内存缓存_Node.js_Graphql_Dataloader - Fatal编程技术网

Node.js 与GraphQL数据加载器一起实现内存缓存

Node.js 与GraphQL数据加载器一起实现内存缓存,node.js,graphql,dataloader,Node.js,Graphql,Dataloader,我正在研究向我的应用程序中添加内存缓存,比如redis,我在理解如何将它们结合在一起时遇到了一些问题 constpostloader=newdataloader(异步键=>{ //…通过ID获取多篇文章的sql代码 }) 常量postRepository={ 异步获取(id){ let post=等待cachingImplementation.get(“post:+id”) 如果(!post){ post=等待postLoader.load(id) } 回程站 } } 我理解对数据库进行批量查

我正在研究向我的应用程序中添加内存缓存,比如redis,我在理解如何将它们结合在一起时遇到了一些问题

constpostloader=newdataloader(异步键=>{
//…通过ID获取多篇文章的sql代码
})
常量postRepository={
异步获取(id){
let post=等待cachingImplementation.get(“post:+id”)
如果(!post){
post=等待postLoader.load(id)
}
回程站
}
}
我理解对数据库进行批量查询的必要性,但对redis服务器的查询是否也适用同样的原则

在这种情况下,如果我在同一时间内运行
postRepository.get
方法10次,我将不得不向redis服务器发出10个不同的请求

这是个问题吗?我是否应该将实际的获取源(缓存或数据库)移动到dataloader解析器中,以便它不直接执行sql代码,而是首先查看缓存,然后查看数据库

比如说

cache = {
  1: ...,
  2: ...
}
如果我请求id为1,2,3的帖子,缓存中只有两个。因此,我必须过滤掉现有的id并在数据库中查询其余的id,或者只检查请求的id是否与返回的行长度匹配,如果不匹配,则查询数据库中的所有内容

这两种方法的缺点是什么?有更好的解决方案吗

  • 向任何数据库发出多个请求与将这些请求聚合为一个请求的主要成本是联网。使用内存中的数据库并不能消除这一成本。因此,我建议您使用数据加载器中的缓存
  • 逐步填充缓存是一种方法,但不要忘记在Redis键上设置一个过期日期,因为如果缓存每个实体,可能很快就会耗尽内存
  • 根据应用程序的不同,API层缓存可能是更好的选择。如果您正在使用GraphQL,请签出

    在我们的系统中,我们称数据加载器为API聚合层。这里要实现的是拥有一个API聚合层缓存。我建议,不管数据模型如何,都要对该缓存进行泛化,并在需要缓存数据加载程序时使用高阶函数

    const memo = (type, loadData) => {
      return async (keys) => {
        { cacheData, notFoundKeys } = loadFromRedis(type, keys);
        let data = cacheData;
        if (notFoundKeys.length > 0) {
          loadedData = await loadData(notFoundKeys);
          populateCache(type, notFoundKeys, data);
          data = addLoadedData(cacheData, loadedData);
        }
        return data;
      }
    }
    
    const postLoaderMemoized = memo('post', async keys => {
      // ... sql code to get multiple posts by ids
    })
    
    const postLoader = new DataLoader(postLoaderMemoized)
    

    我确实浏览了Apollo文档的缓存,但是除了超时之外,它们似乎没有提供过期机制。我正在开发的应用程序允许用户创建帖子和其他实体,并对其进行编辑,因此基于时间的过期不太合适,至少乍一看不合适。我有必要手动使缓存因某些突变而无效。他们是否恰好提供了一个我错过的API?因此,Redis(数据加载器)缓存可能是一个不错的选择(我上面的解决方案是针对Redis缓存的)。我刚才提到Apollo缓存,因为它有时更适合某些应用程序。我仍然认为,除了缓存失效之外,您还需要使用Redis expirations。在ReDIS中存储所有被查看的帖子可能会很快填充你的机器内存,除非你的帖子数量有限。是的,我将使用过期超时,但是它们通常比我考虑的阿波罗缓存要长。您是否知道有哪些模式允许将“关注点”分开一点,因为我不太喜欢将缓存查询与数据库查询混合在一起,它们似乎耦合得太紧密。我们在数据访问层发出数据库请求,我们的平台(应用程序)层功能然后调用数据层访问数据库,最后,我们从API聚合层(数据加载器)调用平台层函数,最后API层调用数据加载器(有时直接调用平台层)。您可以将Redis缓存放在这些层之前,但我喜欢使用高阶函数的API聚合层缓存(在您的例子中)。我还建议您看看是否正在使用SQL,是否需要一个更有组织的数据访问层。