当前位置:首页 > 科技  > 软件

SaaS多租户架构数据源动态切换解决方案

来源: 责编: 时间:2024-03-28 17:51:58 247观看
导读概述随着云计算和SaaS(Software as a Service)模型的兴起,多租户系统成为了构建灵活、高效应用的重要架构。在构建多租户SaaS平台时,数据库方案的选择直接关系到数据隔离、性能和可扩展性。在SaaS平台项目中,根据前端不同

概述

随着云计算和SaaS(Software as a Service)模型的兴起,多租户系统成为了构建灵活、高效应用的重要架构。在构建多租户SaaS平台时,数据库方案的选择直接关系到数据隔离、性能和可扩展性。Eyn28资讯网——每日最新资讯28at.com

在SaaS平台项目中,根据前端不同的域名查询不同的数据库,通常涉及到多租户架构的实现。在这种架构中,一个应用实例可以服务多个客户(租户)【数据库】,每个租户的数据需要隔离存储。实现这一目标的关键技术之一就是动态切换数据库连接。Eyn28资讯网——每日最新资讯28at.com

设计多租户数据模型

在数据库设计阶段,你需要决定数据隔离的级别。通常有以下几种隔离级别:Eyn28资讯网——每日最新资讯28at.com

  • 独立数据库:每个租户拥有一个独立的数据库实例。
  • 共享数据库,独立Schema:所有租户共享同一个数据库,但每个租户有独立的Schema。
  • 共享数据库,共享Schema,共享数据表:所有租户共享数据库、Schema和数据表,但通过租户ID字段进行数据隔离。

共享数据库,独立Schema

"共享数据库,独立Schema" 是一种在SaaS平台中实现多租户架构的策略,它在数据库层面上提供了一种折中的数据隔离方法。Eyn28资讯网——每日最新资讯28at.com

Oracle数据库:在Oracle中一个数据库可以具有多个用户,那么一个用户一般对应一个Schema,表都是建立在Schema中的,(可以简单的理解:在Oracle中一个用户一套数据库表)Eyn28资讯网——每日最新资讯28at.com

图片图片Eyn28资讯网——每日最新资讯28at.com

在 MySQL 中,Schema 和 Database 可以认为是相同的概念。在 SQL 语句中,CREATE DATABASE 和 CREATE SCHEMA 基本上是等效的。所以,当你创建一个数据库时,你也在事实上创建了一个模式。模式是一个逻辑上的容器,用于组织和管理数据库对象,如表、视图、存储过程等。在 MySQL 中,模式和数据库可以互换使用。Eyn28资讯网——每日最新资讯28at.com

共享数据库

在这种模式下,所有的租户(即SaaS平台的客户)共享同一个物理数据库服务器或数据库实例。这意味着,尽管每个租户都有自己的数据,但这些数据都存储在同一个数据库文件或数据库集群中。这样做的好处是可以减少硬件资源和维护成本,因为不需要为每个租户单独设置和维护数据库实例。Eyn28资讯网——每日最新资讯28at.com

独立Schema

尽管数据库是共享的,但每个租户都有自己独立的Schema。Schema是数据库中的一种逻辑分组,它包含了一系列的数据库对象,如表、视图、索引、存储过程等。在这个模式下,每个租户的数据都存储在自己的Schema中,这样可以保证租户之间的数据逻辑上是隔离的。Eyn28资讯网——每日最新资讯28at.com

例如,假设有两个租户A和B,他们共享同一个数据库"SaaSDB"。在"SaaSDB"中,可以分别为租户A和租户B创建两个Schema(数据库),分别是"SchemaA"和"SchemaB"。租户A的所有数据都存储在"SchemaA"中,而租户B的数据存储在"SchemaB"中。Eyn28资讯网——每日最新资讯28at.com

优缺点

优点
  1. 资源利用率高:由于所有租户共享同一个数据库,硬件资源和数据库维护成本较低。
  2. 易于管理:数据库管理员只需要管理一个数据库实例,简化了维护和升级的工作。
  3. 隔离性:每个租户的数据存储在独立的Schema中,逻辑上实现了数据隔离,减少了数据交叉污染的风险。
缺点
  1. 隔离性不如独立数据库:虽然Schema提供了一定程度的隔离,但如果Schema之间存在依赖关系或需要进行复杂的数据操作,隔离性可能不如完全独立的数据库。
  2. 性能问题:如果租户数量增多,可能会导致数据库性能问题,因为所有租户都在竞争同一个数据库资源。

总体来说,"共享数据库,独立Schema" 的模式在SaaS平台中是一种常见的多租户数据隔离策略,它在资源利用率和数据隔离性之间取得了平衡。开发者需要根据具体的业务需求和预期的租户规模来决定是否采用这种模式。Eyn28资讯网——每日最新资讯28at.com

SaaS多租户架构数据库设计

重点:在 SQL 语句中,CREATE DATABASE 和 CREATE SCHEMA 基本上是等效的。所以,当你创建一个SCHEMA时,就是在一个RDS实例下创建一个数据库DATABASE。Eyn28资讯网——每日最新资讯28at.com

图片图片Eyn28资讯网——每日最新资讯28at.com

以newtrain.tinywan.com、hz_newtrain.tinywan.com、bj_newtrain.tinywan.com三个域名为例,每个域名对应一个租户平台站点,分别对应各自的数据源数据库newtrain.tinywan.com、hangzhou.tinywan.com、beijing.tinywan.com。Eyn28资讯网——每日最新资讯28at.com

实施方案

域名解析与路由

  • 在DNS系统中为每个域名配置A记录,指向SaaS平台的服务器
  • 在服务器上部署Web应用,并根据请求的Host头部信息,确定租户身份。

数据源配置

  • 在应用程序的配置文件中,定义每个租户的数据源配置,包括数据库URL、用户名和密码
  • 可以使用环境变量或配置中心来动态加载这些配置。

动态数据源切换

根据请求的域名或其他标识符,动态确定使用哪个数据库连接。这通常通过中间件、拦截器或全局函数来实现。Eyn28资讯网——每日最新资讯28at.com

示例:使用PHP实现域名路由中间件Eyn28资讯网——每日最新资讯28at.com

<?php/** * @desc 域名路由中间件 * @author Tinywan(ShaoBo Wan) * @date 2024/11/20 18:14 */declare(strict_types=1);namespace app/middleware;use app/common/model/SaasModel;use Webman/Http/Request;use Webman/Http/Response;use Webman/MiddlewareInterface;class ConnectionMiddleware implements MiddlewareInterface{    /**     * @param Request $request     * @param callable $handler     * @return Response     */    public function process(Request $request, callable $handler): Response    {        $domain = $request->header()['x-site-domain']?? 'https://newtrain.tinywan.com';        $platform = SaasModel::where('domain', $domain)->field('id, domain, website')->findOrEmpty();        if (!$platform->isEmpty()) {            $request->website = $platform['website'];        }        return $handler($request);    }}

以上根据前端请求的域名标识符x-site-domain,动态确定使用哪个数据库连接,通过中间件动态赋予全局请求对象$request->website,后续就可以使用。Eyn28资讯网——每日最新资讯28at.com

项目应用

项目架构

项目使用超高性能可扩展PHP框架webman。webman是一款基于workerman开发的高性能HTTP服务框架。webman用于替代传统的php-fpm架构,提供超高性能可扩展的HTTP服务。你可以用webman开发网站,也可以开发HTTP接口或者微服务。Eyn28资讯网——每日最新资讯28at.com

数据库连接使用ThinkORM。ThinkORM是一个基于PHP和PDO的数据库中间层和ORM类库,之前一直作为ThinkPHP5.*系列的内置ORM类,以优异的功能和突出的性能著称,现已经支持独立使用,并作了升级改进,提供了更优秀的性能和开发体验,最新版本要求PHP7.1+。Eyn28资讯网——每日最新资讯28at.com

数据库连接中间

示例:域名路由中间件Eyn28资讯网——每日最新资讯28at.com

<?php/** * @desc 域名路由中间件 * @author Tinywan(ShaoBo Wan) * @date 2024/11/20 18:14 */declare(strict_types=1);namespace app/middleware;use app/common/model/SaasModel;use Webman/Http/Request;use Webman/Http/Response;use Webman/MiddlewareInterface;class ConnectionMiddleware implements MiddlewareInterface{    /**     * @param Request $request     * @param callable $handler     * @return Response     */    public function process(Request $request, callable $handler): Response    {        $domain = $request->header()['x-site-domain']?? 'https://newtrain.tinywan.com';        $platform = SaasModel::where('domain', $domain)->field('id, domain, website')->findOrEmpty();        if (!$platform->isEmpty()) {            $request->website = $platform['website'];        }        return $handler($request);    }}

数据库配置

ThinkORM配置文件:config/thinkorm.phpEyn28资讯网——每日最新资讯28at.com

<?php/** * @desc ThinkORM配置文件 * @author Tinywan(ShaoBo Wan) * @date 2024/11/14 15:14 */declare(strict_types=1);return [    'default' => 'train',    'connections' => [        'train' => [            'type' => 'mysql',            'hostname' => '127.0.0.1',            'database' => 'newtrain.tinywan.com',            'username' => 'root',            'password' => '123456'        ],        'hangzhou' => [            'type' => 'mysql',            'hostname' => '127.0.0.1',            'database' => 'hangzhou.tinywan.com',            'username' => 'root',            'password' => '123456'        ],        'beijing' => [            'type' => 'mysql',            'hostname' => '127.0.0.1',            'database' => 'beijing.tinywan.com',            'username' => 'root',            'password' => '123456'        ]    ],];

Model模型使用

BaseModel.php 基础模型Eyn28资讯网——每日最新资讯28at.com

<?php/** * @desc 基础模型 * @author Tinywan(ShaoBo Wan) * @date 2024/11/2 15:09 */declare(strict_types=1);namespace app/common/model;use think/Model;class BaseModel extends Model{    /**     * 设置当前模型的数据库连接     * @var string     */    protected $connection;    /**     * BaseModel constructor.     * @param array $data     */    public function __construct(array $data = [])    {        $this->connection = /request()->website ?? 'train';        parent::__construct($data);    }}

CityModel.php 公共模型,对应数据库表名common_city。Eyn28资讯网——每日最新资讯28at.com

<?php/** * @desc 市模型 * @author Tinywan(ShaoBo Wan) * @date 2024/12/13 14:59 */declare(strict_types=1);namespace app/common/model;use think/Model;class CityModel extends Model{    /** 数据库配置 */    protected $connection = 'train';    /** 设置当前模型对应的完整数据表名称 */    protected $table = 'common_city';}

公共模型CityModel类里面定义了connection属性,则该模型操作的时候会自动按照给定的数据库配置进行连接,而不是配置文件中设置的默认连接信息.Eyn28资讯网——每日最新资讯28at.com

业务 MeetingModel.php 会议模型类。对应数据库表名resty_meetingEyn28资讯网——每日最新资讯28at.com

<?php/** * @desc 会议模型类 * @author Tinywan(ShaoBo Wan) * @date 2024/11/17 11:55 */declare(strict_types=1);namespace app/common/model;class MeetingModel extends BaseModel{    /** 设置当前模型对应的完整数据表名称 */    protected $table = 'resty_meeting';}

业务控制器或者服务使用Eyn28资讯网——每日最新资讯28at.com

<?php/** * @desc 会议 * @author Tinywan(ShaoBo Wan) * @date 2023/11/9 16:57 */declare(strict_types=1);public function meetingList(/support/Request $request, int $organizationId) : /support/Response{    $meetingList = /app/common/model/MeetingModel::where([        'organization_id' => $organizationId,        'create_user_id' => $this->userId    ])->select();    return json($meetingList->toArray());}

Db类使用

可以调用Db::connect方法动态配置数据库连接信息Eyn28资讯网——每日最新资讯28at.com

<?php/** * @desc 会议 * @author Tinywan(ShaoBo Wan) * @date 2023/11/9 16:57 */declare(strict_types=1);public function datasetList(/support/Request $request) : /support/Response{    $res = /think/facade/Db::connect(/request()->website)        ->table('resty_meeting')        ->field('id,name')        ->select();    return json($res->toArray());}

connect方法必须在查询的最开始调用,而且必须紧跟着调用查询方法,否则可能会导致部分查询失效或者依然使用默认的数据库连接。动态连接数据库的connect方法仅对当次查询有效。这种方式的动态连接和切换数据库比较方便,经常用于多数据库连接的应用需求。Eyn28资讯网——每日最新资讯28at.com

动态连接到目标数据库

在SaaS平台中,如果需要根据前端传递的配置信息动态连接到目标数据库并将数据拉取到本地数据库,可以采用以下步骤实现Eyn28资讯网——每日最新资讯28at.com

  • 前端传递配置信息。前端在用户操作时,将目标数据库的连接信息作为请求参数发送到后端。这些配置信息通常包括数据库类型、主机地址、端口、数据库名、用户名和密码等。
  • 验证和解析配置信息。后端接收到配置信息后,首先进行验证,确保其合法性和安全性。解析配置信息,并准备用于数据库连接的参数。
  • 动态数据源管理。创建一个动态数据源管理器,它可以根据传入的配置信息动态创建数据库连接。
  • 数据同步。根据目标数据库的连接信息,建立连接并执行数据查询操作。然后将查询结果同步到本地数据库。这可能涉及到以下步骤:

建立连接:使用动态数据源管理器创建的目标数据库连接。Eyn28资讯网——每日最新资讯28at.com

执行查询:在目标数据库上执行SQL查询,获取所需数据。Eyn28资讯网——每日最新资讯28at.com

映射数据:将查询结果映射到本地数据库的表结构中。Eyn28资讯网——每日最新资讯28at.com

写入本地数据库:将映射后的数据插入到本地数据库中。Eyn28资讯网——每日最新资讯28at.com

  • 异常处理和日志记录。在整个数据同步过程中,需要妥善处理可能出现的异常情况,并记录相关操作日志,以便于问题追踪和系统维护。
  • 安全性考虑
  • 加密敏感信息:确保所有的数据库凭证信息在存储和传输过程中都是加密的。Eyn28资讯网——每日最新资讯28at.com

  • 权限控制:确保只有授权的用户或服务才能访问数据同步功能。Eyn28资讯网——每日最新资讯28at.com

  • SQL注入防护:对动态执行的SQL进行严格的安全检查,避免SQL注入攻击。Eyn28资讯网——每日最新资讯28at.com

自定义函数

函数配置文件app/functions.php新增函数dynamic_connect_db()Eyn28资讯网——每日最新资讯28at.com

/** * @desc: 动态切换数据库 * @param string $name * @param array $connection * @return /think/db/ConnectionInterface * @author Tinywan(ShaoBo Wan) */function dynamic_connect_db(string $name, array $connection): /think/db/ConnectionInterface{    try {        $connect = /think/facade/Db::connect($name);    } catch (/Throwable $e) {        // 获取配置参数        $config  = /think/facade/Db::getConfig();        // 配置具体的数据库连接信息        $config['connections'][$name] = $connection;        // 初始化配置参数        /think/facade/Db::setConfig($config);        // 创建/切换数据库连接查询        $connect = /think/facade/Db::connect($name);    }    return $connect;}

动态使用

调用自定义函数dynamic_connect_db()方法动态数据库连接查询,这里查询一个不存在的配置数据库zhejiang 浙江站点。Eyn28资讯网——每日最新资讯28at.com

/** * @desc: 动态切换数据库 * @param Request $request * @return Response * @throws DataNotFoundException * @throws DbException * @throws ModelNotFoundException * @author Tinywan(ShaoBo Wan) */public function dynamicConnectDb(Request $request): Response{    $connection = [        'type' => 'mysql',        'hostname' => '127.0.0.1',        'database' => 'zhejiang.tinywan.com',        'username' => 'root',        'password' => '123456'    ];    $connect = dynamic_connect_db('zhejiang', $connection);    $result = $connect->table('resty_meeting')->where('id', 1)->find();    var_dump($result);    return json($result->toArray());}

在实际应用中,数据同步操作可能涉及到复杂的数据映射和处理逻辑,需要根据具体的业务需求进行设计和实现。同时,为了保障系统的稳定性和性能,可能还需要考虑引入事务管理、批量处理和异步处理等机制。Eyn28资讯网——每日最新资讯28at.com

Eyn28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-80200-0.htmlSaaS多租户架构数据源动态切换解决方案

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 使用 HexFormat 来格式化和解析十六进制字符串

下一篇: 功能问题:如何用Docker部署一个后端项目?

标签:
  • 热门焦点
  • 印度登月最关键一步!月船三号今晚进入环月轨道

    8月5日消息,据印度官方消息,月船三号将于北京时间今晚21时30分左右开始近月制动进入环月轨道。这是该探测器能够成功的最关键步骤之一,如果成功将开始围
  • 十个简单但很有用的Python装饰器

    装饰器(Decorators)是Python中一种强大而灵活的功能,用于修改或增强函数或类的行为。装饰器本质上是一个函数,它接受另一个函数或类作为参数,并返回一个新的函数或类。它们通常用
  • 虚拟键盘 API 的妙用

    你是否在遇到过这样的问题:移动设备上有一个固定元素,当激活虚拟键盘时,该元素被隐藏在了键盘下方?多年来,这一直是 Web 上的默认行为,在本文中,我们将探讨这个问题、为什么会发生
  • Python异步IO编程的进程/线程通信实现

    这篇文章再讲3种方式,同时讲4中进程间通信的方式一、 Python 中线程间通信的实现方式共享变量共享变量是多个线程可以共同访问的变量。在Python中,可以使用threading模块中的L
  • 使用AIGC工具提升安全工作效率

    在日常工作中,安全人员可能会涉及各种各样的安全任务,包括但不限于:开发某些安全工具的插件,满足自己特定的安全需求;自定义github搜索工具,快速查找所需的安全资料、漏洞poc、exp
  • 电视息屏休眠仍有网络上传 爱奇艺被质疑“薅消费者羊毛”

    记者丨宁晓敏 见习生丨汗青出品丨鳌头财经(theSankei) 前不久,爱奇艺发布了一份亮眼的一季报,不仅营收和会员营收创造历史最佳表现,其运营利润也连续6个月实现增长。自去年年初
  • 自研Exynos回归!三星Galaxy S24系列将提供Exynos和骁龙双版本

    年初,全新的三星Galaxy S23系列发布,包含Galaxy S23、Galaxy S23+和Galaxy S23 Ultra三个版本,全系搭载超频版骁龙8 Gen 2,虽同样采用台积电4nm工艺制
  • iQOO Neo8系列新品发布会

    旗舰双芯 更强更Pro
  • 电博会与软博会实现"线下+云端"的双线融合

    在本次“电博会”与“软博会”双展会利好条件的加持下,既可以发挥展会拉动人流、信息流、资金流实现快速交互流动的作用,继而推动区域经济良性发展;又可以聚
Top