VonaJS提供的读写分离,直观,优雅🌼

在VonaJS中实现读写分离,只需提供一组写数据源和一组读数据源。当用户访问后端 API 时,系统会按照规则自动选择写数据源或读数据源,访问相应的数据库,从而分摊压力,提升系统性能

安装模块

读写分离作为独立的模块提供,因此需要在VonaJS项目中安装此模块:

bash 复制代码
$ pnpm add vona-module-a-datasharding -w

添加数据源

首先,需要添加一组数据源

1. 添加类型定义

为新数据源添加类型定义

src/backend/config/config/config.ts

typescript 复制代码
declare module 'vona-module-a-orm' {
  export interface IDatabaseClientRecord {
    read1: never;
    read2: never;
    write1: never;
    write2: never;
  }
}

2. 增加数据源配置

src/backend/config/config/config.ts

typescript 复制代码
// database
config.database = {
  clients: {
    read1: {
      client: 'pg',
      connection: {
        host: '127.0.0.1',
        port: 5432,
        user: 'postgres',
        password: '',
        database: 'xxxx-read1',
      },
    },
    read2: {...},
    write1: {...},
    write2: {...},
  },
};

配置读写数据源

然后配置模块的读写数据源

src/backend/config/config/config.ts

typescript 复制代码
// modules
config.modules = {
  'a-datasharding': {
    client: {
      reads: ['read1', 'read2'],
      writes: ['write1', 'write2'],
      randomRead: undefined,
      randomWrite: undefined,
    },
  },
};    
名称 说明
reads 指定一组读数据源
writes 指定一组写数据源
randomRead 可指定自定义函数,从reads中提取一个读数据源。默认为undefined,由系统随机提取
randomWrite 可指定自定义函数,从writes中提取一个写数据源。默认为undefined,由系统随机提取

读写分离的运行机制

当配置好读写数据源之后,读写分离机制就自动生效了

现在,解释一下读写分离的运行机制:

模块提供了一个全局拦截器a-datasharding:datasharding。该拦截器判断当前 API Method,如果是POST/PATCH/DELETE/PUT,那么就使用写数据源,否则使用读数据源

数据一致性: 缓存写数据源

场景分析:同一个用户

由于数据库同步有延时,会出现数据不一致性的情况。比如,用户访问Write-API,将数据写入写数据库。接下来,用户访问Read-API,此时读数据库还没有同步,那么就会读到旧数据

为了解决以上问题,模块自动提供了一个机制:当用户访问Write-API时,会自动将写数据源存入二级缓存,并设置过期时间。在这个时间之内,用户访问Read-API时,也会继续使用同一个写数据源,从而确保在写入数据后总是可以读取到最新的数据

修改过期时间

二级缓存的名称是a-datasharding:datasourceWrite,可以在 App config 中修改过期时间:

src/backend/config/config/config.ts

typescript 复制代码
// onions
config.onions = {
  summerCache: {
    'a-datasharding:datasourceWrite': {
      mem: {
        ttl: 5 * 1000, // 5s
      },
      redis: {
        ttl: 5 * 1000, // 5s
      },
    },
  },
};
名称 说明
mem.ttl Mem缓存的过期时间,默认为3秒
redis.ttl Redis缓存的过期时间,默认为3秒

数据一致性: 缓存双删

场景分析:不同用户

Vona ORM 提供了开箱即用的缓存机制,参见:缓存

由于数据库同步有延时,会出现缓存不一致性的情况。比如,用户 A 访问Write-API,将数据写入写数据库,并自动删除缓存。接下来,用户 B 访问Read-API,此时读数据库还没有同步,那么就会读到旧数据,并存入缓存

为了解决以上问题,模块a-orm提供了缓存双删机制:当用户 A 访问Write-API时,将数据写入写数据库,并自动删除缓存。然后在指定时间之后再次删除缓存,从而确保缓存总是最新数据

启用缓存双删

src/backend/config/config/config.ts

typescript 复制代码
// modules
config.modules = {
  'a-orm': {
    sharding: {
      cache: {
        doubleDelete: true,
      },
    },
  },
};

修改缓存双删延迟时间

系统采用队列任务执行缓存双删,队列名称是a-orm:doubleDelete,可以在 App config 中修改缓存双删延迟时间:

src/backend/config/config/config.ts

typescript 复制代码
// onions
config.onions = {
  queue: {
    'a-orm:doubleDelete': {
      options: {
        job: {
          delay: 5 * 1000, // 5s
        },
      },
    },
  },
};
名称 说明
job.delay 指定延迟多长时间执行缓存双删任务,默认为3秒

Vona ORM已开源:https://github.com/vonajs/vona

相关推荐
程序员Sunday10 小时前
TypeScript 的 any、unknown、never 有什么区别?
前端·面试·typescript
三十而立洋16 小时前
TypeScript 7.0 深度解析:新特性、Go 原生编译器及与 TypeScript 6.0 的区别
前端·typescript·前端工程化
VimorphTech16 小时前
React 自动保存怎么设计?防抖、串行请求与导出前等待
后端·typescript
yuanlaile20 小时前
做了 3 年后端才明白:学 NestJS 千万不要只学 API 语法,完整电商项目才是分水岭
typescript·nestjs·node.js 后端·nestjs实战
ZoeLandia20 小时前
TypeScript 07:工程化——import type、声明文件与 tsconfig
开发语言·前端·typescript
nyaomaru1 天前
如何用 Jev 从 PR 中提取 “Why” 并写入 CHANGELOG?🤔
前端·typescript
damoluomu1 天前
SSG 的后台怎么补:Node.js 生态里的三条路(番外二)
javascript·css·typescript·node.js·html
苏渡苇1 天前
从零搭建 Vue 3 工程化项目:Vite + TypeScript + Pinia + Element Plus 实战
前端·vue.js·typescript
濮水大叔1 天前
NestJS Dynamic Providers 与 Cabloy/Vona Provider Scene:同接口多实现的两种装配哲学
typescript·node.js·nestjs
const_qiu2 天前
第一章 1.1-1.2:基础模型调用与 TypeScript 入门 —— Java 开发者的视角
java·javascript·typescript