你们在 Go 项目中如何实现分表读写的?插件?手写?代理?

2023-03-21 11:04:47 +08:00
 RedisMasterNode

苦于写了很多重复代码,想了解一下大家在 Go 的项目里面是怎么用 GORM (或者其他 MySQL 客户端,不限 ORM / Raw SQL )来实现分表读写的?

例如 user_tab_00000000 - user_tab_00000199,一共 200 张表,按 user_id % 200 来分表。

了解过的方案:

  1. DAO 层(或操作 DB 层)时根据传入参数计算,相关代码会出现在每个 Query 方法,例如 CreateUser()GetUserByUserID()UpdateUserByUserID()
  2. 挂载插件,init 时定义、注册分表字段、分表算法等等,DAO 层无特殊处理(就像在操作单表一样),实际执行的时候被改写,例如应用里执行 SELECT * FROM user_tab WHERE user_id = 199 最终会被改写成 SELECT * FROM user_tab_00000199 WHERE user_id = 199 发往 MySQL ;
  3. 应用层外挂载 MySQL 的代理,类似 ShardingSphere 这种,流程跟方案 2 类似,只是改写由外部中间件完成。

个人感觉方案 2 是个挺好的思路但是 Go 里面好像没有什么特别好用的中间件。

4500 次点击
所在节点    Go 编程语言
38 条回复
dobelee
2023-03-21 11:14:06 +08:00
存储层手动调不同的读写实例。稳健。
p23XnFNH1Wq953rV
2023-03-21 11:17:46 +08:00
如果可以的话, 让业务同学更专心写业务吧, 分表这种交给运维
如果没条件, 只能自己搞, 2 更好一些
RedisMasterNode
2023-03-21 11:19:02 +08:00
@dobelee 我们也是这么做的,确实稳健,所有的流程都能在 debug 的时候看清楚,其实就是相当于嵌入业务了,能感知到,坏处在于多加几行代码,库表越多,写得越多
dobelee
2023-03-21 11:26:35 +08:00
@RedisMasterNode 也不用加什么代码,微服务下单个服务一般不会管理太多库表。相反我认为下层自动读写分离反而不太好,如特殊情况就得在主库做查询呢?脱离开发控制了。还是看实际情况吧,没遇到什么问题维持现状即可。
RedisMasterNode
2023-03-21 11:27:35 +08:00
@dobelee 在理
Nooooobycat
2023-03-21 11:31:31 +08:00
直接上分布式的数据库
RedisMasterNode
2023-03-21 11:32:07 +08:00
@Nooooobycat 也是个解决方案
zhongjun96
2023-03-21 11:33:41 +08:00
好奇分这么多表,列表查询怎么做的?
EAFA0
2023-03-21 11:43:37 +08:00
在 grom 上单写一个 table 方法, 接收相关分表参数, 返回一个 gorm.DB 对象, 然后每次都调用 table 方法获取对应 gorm.DB 对象就好了

类似于
``` golang

func (d UserDao) table(userID int64) *gorm.DB {
return mysql.Client("user").Table(fmt.Sprintf("user_table_%d", userID%1000))
}

```
xuanbg
2023-03-21 11:56:54 +08:00
分库:配置中心实现不同服务实例连不同的库
分表:程序中按规则拼表名

简单粗暴,但效果非常好。
RedisMasterNode
2023-03-21 12:18:30 +08:00
@zhongjun96 一般有扫表的方案和异构存储 /离线数仓的方案;另外在决定分表之前也是需要考虑业务是否要频繁的批量查询,如果非常多批量操作的话,设计的时候要看能不能把分表依据和批量操作的依据结合起来,或者不用分表的方案实现
RedisMasterNode
2023-03-21 12:18:58 +08:00
@EAFA0 嗯嗯是个方案,我们现在也在用这样的写法
noparking188
2023-03-21 12:31:13 +08:00
听播客,PingCAP 的 CTO 说他也遇到这种问题,然后就开发了 TiDB
zeonll
2023-03-21 12:56:10 +08:00
@zhongjun96 一个用户的数据一般都在一个表内。跨用户查询的 case 比较少吧
OutOfMemoryError
2023-03-21 12:58:14 +08:00
mysql 的分区表,直接从数据库引擎层解决
Famio
2023-03-21 13:31:35 +08:00
为啥不用分区表搞啊,还要代码逻辑去判断有点。。。

ALTER TABLE table_name PARTITION BY RANGE COLUMNS(userid) (
PARTITION p1 VALUES LESS THAN (200),
PARTITION p2 VALUES LESS THAN (400),
PARTITION p3 VALUES LESS THAN (600),
PARTITION p4 VALUES LESS THAN (MAXVALUE)
);

多香
lopssh
2023-03-21 14:16:07 +08:00
@EAFA0 咋扩容?如果后面扩展到了 999 个表。。。你这个 UserID 算出来的结果不一致了咋办。
kiddingU
2023-03-21 14:23:44 +08:00
gorm 好像有 db resolve 插件,这玩意自己写也比较方便吧
ZeroDu
2023-03-21 14:24:13 +08:00
方案 2 吧 ShardingSphere 就是实现的这种;直接在 jdbc 层动手脚,跟 orm 框架无关;至于 go 这边就不清楚了;

或者直接上分布式数据库
echo1937
2023-03-21 14:48:16 +08:00
前排求推荐开源的分布式 OLTP 数据库,大家用哪个比较多 ?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/925774

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX