V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
MySQL 5.5 Community Server
MySQL 5.6 Community Server
Percona Configuration Wizard
XtraBackup 搭建主从复制
Great Sites on MySQL
Percona
MySQL Performance Blog
Severalnines
推荐管理工具
Sequel Pro
phpMyAdmin
推荐书目
MySQL Cookbook
MySQL 相关项目
MariaDB
Drizzle
参考文档
http://mysql-python.sourceforge.net/MySQLdb.html
lostSoul
V2EX  ›  MySQL

多租户系统,采用 PostgreSQL 好还是 Mysql 好

  •  1
     
  •   lostSoul · 2021-05-11 15:10:26 +08:00 · 8185 次点击
    这是一个创建于 1271 天前的主题,其中的信息可能已经有所发展或是发生改变。

    saas 类型的系统,目前是采用了最 low 的行级多租户,也就是每个表加一个 tenantId,然后用代码逻辑隔离,现在随着系统的用户增长,很多问题随着出现了,维护麻烦,性能低效,代码逻辑复杂混乱
    于是决定重构,打算采用多租户的另外一套方案,单库多 schema,但查阅了资料,发现 mysql 根本没有真正意义上的 schema,或者说 schema 就是 database
    再后来了解到 PostgreSql,感觉国内资料挺少的,用的也很少,但看到一些比较资料发现他比 mysql 好太多了,但又怕上了踩坑,而且还要数据迁移之类的,有没有大佬给个方案

    第 1 条附言  ·  2021-05-11 15:56:39 +08:00
    我这边总结了几个方案,先说说传统的解决方案:
    数据隔离有三种方案:
    1 、独立数据库:简单来说就是一个租户使用一个数据库,这种数据隔离级别最高,安全性最好,但是提高成本。
    2 、共享数据库、隔离数据架构:多租户使用同一个数据裤,但是每个租户对应一个 Schema(数据库 user)。
    3 、共享数据库、共享数据架构:使用同一个数据库,同一个 Schema,但是在表中增加了租户 ID 的字段,这种共享数据程度最高,隔离级别最低。

    目前我的系统采用了最 low 的第三个方案,我是强烈不推荐这个方案,迫不得已才用它,因为他只会加重数据的维护难度和让代码变得异常复杂,我是使用了 myabtis 的插件来拦截,但是当一些场景复杂后你的 SQL 不得不吐血

    所以我把矛头指向了 postgreSql,因为他天生就自带支持多个多租户的方案,但因为国内资料少,坑多,数据迁移也是问题,故无法采用。

    最后我决定采用 Mysql + MyCat (中间件,基于阿里开源的 cobar 演变而来)+Mybatis,之所以采用 MyCat,因为他提供了多租户的解决方案,同时增强了 mysql 的处理性能了,最重要的是 mycat 更新也很社区活跃算是可以,同时提供了丰富的文档
    第 2 条附言  ·  2021-05-11 16:03:18 +08:00
    有更好的解决方案欢迎大佬提出,感谢!
    第 3 条附言  ·  2021-05-12 16:02:45 +08:00
    感谢各位大佬的回复,评论很多说第三套方案不 low,其实我要表达的不是单单的 low,而是想表达太简单粗暴,后面我想了想,也对,三个方案其实都好,但是要结合实际出发


    首先是如何选择方案,主要考虑的首先是安全和成本,安全决定了隔离级别
    我们应该从多个方面来选择方案,而不是哪个方案 low 不 low

    首先考虑成本,1 块钱掰成两份花,隔离越低则成本越低,相对维护成本也会下降,但安全性也会随之下降。

    其次是安全因素:要考虑业务和客户的安全方面的要求。安全性要求越高,越要倾向于隔离。

    所以必须从多个方面去考虑:
    38 条回复    2021-05-12 23:25:24 +08:00
    czyt
        1
    czyt  
       2021-05-11 15:22:01 +08:00
    有迁移数据库的需求,建议开发的时候用 orm
    ez728s
        2
    ez728s  
       2021-05-11 15:27:10 +08:00
    怕不是因为方案 low
    xiaoxinshiwo
        3
    xiaoxinshiwo  
       2021-05-11 15:28:36 +08:00
    淘宝算不算多租户系统?
    lostSoul
        4
    lostSoul  
    OP
       2021-05-11 15:40:03 +08:00
    @ez728s 就是因为方案 low 才改的 我现在已经想到另外一方案 采用 Mysql+MyCat 中间件,采用 mycat 去增强 mysql 的功能,mycat 中间件提供了多租户方案,实现 SQL 方式切换数据源
    emmettwoo
        5
    emmettwoo  
       2021-05-11 15:44:10 +08:00
    插眼等老哥们的方案,这种用数据库字段隔离然后代码去判断真的太难受了。
    312ybj
        6
    312ybj  
       2021-05-11 15:48:46 +08:00   ❤️ 1
    我们公司的数据隔离级别就是单独 schema, 使用 myact 拦截 sql,从而导向不同的数据库。redis 也这样干的。
    BQsummer
        7
    BQsummer  
       2021-05-11 15:52:38 +08:00
    租户 id 放 theadlocal,自定义个 mybatis 插件,自动补全租户 id 的查询条件,在业务层面不需要额外处理租户的信息,还是体验可以的。好处是数据库层可以简单化,没啥 low 不 low 的。
    wangxiaoaer
        8
    wangxiaoaer  
       2021-05-11 15:53:32 +08:00   ❤️ 1
    ”现在随着系统的用户增长,很多问题随着出现了,维护麻烦,性能低效,代码逻辑复杂混乱“

    租户表示我不背这个锅。
    johnsona
        9
    johnsona  
       2021-05-11 15:56:29 +08:00 via iPhone
    @emmettwoo 判断 tenantid 是吧
    orm 的方案的话可以 hook 一下自动带上 tenantid
    FightPig
        10
    FightPig  
       2021-05-11 15:57:14 +08:00   ❤️ 1
    不建议 schema 模式,tenantId 模式挺好的,schema 随着用户多起来,你会发现很头疼,如果你再有要查询多租户信息的需求,你就要崩溃了
    lostSoul
        11
    lostSoul  
    OP
       2021-05-11 15:58:39 +08:00
    @wangxiaoaer 哈哈 不被也得背啊 没办法 现在新建一个商户 虽然他看不到其他租户的数据 但都等于他有 100W 条数据了 大家同一条船迟早都得淹死
    lostSoul
        12
    lostSoul  
    OP
       2021-05-11 15:59:34 +08:00
    @FightPig 查询多租户需求也是可以满足的吧 我目前这个方案而言 我们已经用血的教训证明 tenantId 并不是长久方案
    tairan2006
        13
    tairan2006  
       2021-05-11 16:10:19 +08:00   ❤️ 1
    你这个思路好奇怪…而且这都 2021 年了,还有人用 Mycat ?

    你直接上 tidb 啊……当然 pg 生态也有 greenplum 之类的
    Huiao
        14
    Huiao  
       2021-05-11 16:14:42 +08:00
    单数据库 多租户表 表名:business_{租户 id} mybatis 插件动态补全表名
    love
        15
    love  
       2021-05-11 16:19:43 +08:00   ❤️ 3
    为什么 tenantId 是最 low 的方案?能列个实际的代码例子吗,我以前的公司也这样,我感觉是最高级的方案,一点不觉得不方便。
    反而一个用户一个数据库才是 low 到爆的方案,维护复杂更不用提了
    ipwx
        16
    ipwx  
       2021-05-11 16:23:28 +08:00   ❤️ 1
    我直觉上,tenantId 是很好的方案。但是得配合分库分表,通过 tenantId 哈希到某个机器的数据库上,每个机器上又存储若干 tenantId 的数据。如果之前的数据库满了就增加机器,哈希函数改一改。如果某个租户变成狗大户就专门给他放到狗大户的机器上,狗大户的机器少放点租户,小用户的机器上多放点用户。
    wangxiaoaer
        17
    wangxiaoaer  
       2021-05-11 16:50:07 +08:00
    @FightPig #10 楼上有老哥提到淘宝,你说这算不算多租户呢,刚开始我还没觉得,但是一细想,也算多租户,每个商家就是一个租户,维护自己的产品。难道这些产品分别放到不同的库里才是优雅?

    你说全部放到一起量大起来迟早淹死,可是我寻思面对这个问题你应该寻求的是海量数据存储、检索的方案,这些应该成熟的吧,什么 nosql 、分布式不行吗?

    另外,我觉得 tenantId (其实就是特么的 UserID 了)方案还有个好处:当后面需要做跨租户统计、分析的时候,明显要比多租户方便吧。
    hbkdsm
        18
    hbkdsm  
       2021-05-11 18:24:12 +08:00   ❤️ 1
    不同意逻辑隔离是最 low 的方案,这是最高效的方案 (虽然牺牲了数据隔离性)

    多 db 和 多 schema 维护成本太高了,大表跑 DDL 痛苦死了
    Salesforce 就是 tenantID 纯逻辑隔离,Zendesk, Freshdesk, GitHub 都是这样
    这是业内最成熟的方案

    库大了,还可以根据 tenantID 做水平分库,PostgreSQL 有 Citus,MySQL 有 ShardingSphere,都可以按照 tenantID 分库。

    还有 TiDB 这种 NewSQL,或者 Vitess 这种方案。
    BBCCBB
        19
    BBCCBB  
       2021-05-11 18:34:37 +08:00
    @hbkdsm Big old, 这些系统得 tenantId 是哪里看的?
    dbskcnc
        20
    dbskcnc  
       2021-05-11 18:35:15 +08:00
    用的 PostgreSql 的话还可以继续用原来的方案的,表针对 tenantID 做 hash 分区,性能和开发都方便
    用中间件感觉还是有点折腾,有条件当然可以上 newsql
    miao1007
        21
    miao1007  
       2021-05-11 19:54:10 +08:00
    万事不绝,ELK 包治百病,用 ELK 索引作为二级主键
    zzl22100048
        22
    zzl22100048  
       2021-05-11 20:06:36 +08:00
    元数据驱动模式做 saas 不是更好么
    zieglar
        23
    zieglar  
       2021-05-11 20:07:13 +08:00
    PostgreSQL 做错了什么要把矛头指向它(
    joesonw
        24
    joesonw  
       2021-05-11 20:18:04 +08:00
    其实这种场合 sqlite 很合适.
    AngryPanda
        25
    AngryPanda  
       2021-05-11 20:21:36 +08:00 via iPhone
    我们 mongodb 分 db 方案
    xuanbg
        26
    xuanbg  
       2021-05-11 21:45:14 +08:00
    第三种增加据的维护难度和让代码变得异常复杂???我怎么一点感觉都无?哦哦,我是手写 SQL,无非就是查询条件增加一个 tenantId = #{tenantId}的条件而已。没事了没事了。
    kaneg
        27
    kaneg  
       2021-05-12 01:45:06 +08:00 via iPhone
    table 加 tennat id 如果能在框架层面做还好。否则纯手动维护,如果碰到粗心的程序员在某些语句中忘了加 tenant id,那后果就不可设想了。在某个项目中碰到过这样的案例:开发在本地测试的时候只有一个 tenant,没有测出这个问题。结果在项目上线后被客户发现看到了其他公司的数据。。。
    zzlhr
        28
    zzlhr  
       2021-05-12 08:45:17 +08:00
    我们系统用 sqlserver 五年了快,就是 low3 方案,加了个 compid
    securityCoding
        29
    securityCoding  
       2021-05-12 10:54:21 +08:00
    tennat id 不是挺好的吗?
    HashV2
        30
    HashV2  
       2021-05-12 11:30:35 +08:00
    哪有什么 low 不 low 的 只看使用场景和需求 能满足的需求的设计就是好设计
    ccppgo
        31
    ccppgo  
       2021-05-12 11:40:56 +08:00
    什么意思, 如果有上万个用户就有上万个库吗,,,
    notejava
        32
    notejava  
       2021-05-12 12:16:35 +08:00
    通过租户 ID 进行数据隔离才是最简单,最好扩展的方案。我目前项目也遇到一模一样的场景。
    lostSoul
        33
    lostSoul  
    OP
       2021-05-12 16:12:52 +08:00
    1.租户处于爆发式增长应该越倾向于共享,因为一旦租户多了起来,不管是单库还是单表多 schema,维护的成本都是巨大的,涉及后期迭代的时间成本也会随即累加(场景:一些对外开放的 Saas 系统,支持用户自主注册使用,而非人工开通或付费开通)
    lostSoul
        34
    lostSoul  
    OP
       2021-05-12 16:23:09 +08:00
    2.租户数量平稳同时租户数据多应该倾向于隔离,使用隔离级别高的有利于对每个租户进行定制化开发而不会影响到其他租户
    lostSoul
        35
    lostSoul  
    OP
       2021-05-12 16:23:41 +08:00
    因为我是新号回复受限只能回复在评论里
    oneforallsoft
        36
    oneforallsoft  
       2021-05-12 18:46:36 +08:00
    @lostSoul
    而且如果租户有各种各样的需求 每个租户都不一样 就应该一个租户一个数据库 一个租户一套代码
    不会互相影响 尤其是在没有足够测试人员的情况下
    solos
        37
    solos  
       2021-05-12 22:18:52 +08:00
    这不是很正常,现在有 tidb / cockroach 这些支持水平扩展的分布式数据库了,更不是问题了
    ccde8259
        38
    ccde8259  
       2021-05-12 23:25:24 +08:00 via iPhone
    MySQL 有分区表……
    直接拿 tenantId 做 Column Partition 就避免发生新租户上来就在查百万表的情况……
    同时 5.7 开始支持索引条件下推……
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2474 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 10:29 · PVG 18:29 · LAX 03:29 · JFK 06:29
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.