Golang Go语言中你们在项目中如何实现分表读写的?插件?手写?代理?
苦于写了很多重复代码,想了解一下大家在 Go 的项目里面是怎么用 GORM (或者其他 MySQL 客户端,不限 ORM / Raw SQL )来实现分表读写的?
例如 user_tab_00000000
- user_tab_00000199
,一共 200 张表,按 user_id % 200
来分表。
了解过的方案:
- DAO 层(或操作 DB 层)时根据传入参数计算,相关代码会出现在每个 Query 方法,例如
CreateUser()
、GetUserByUserID()
、UpdateUserByUserID()
- 挂载插件,init 时定义、注册分表字段、分表算法等等,DAO 层无特殊处理(就像在操作单表一样),实际执行的时候被改写,例如应用里执行
SELECT * FROM user_tab WHERE user_id = 199
最终会被改写成SELECT * FROM user_tab_00000199 WHERE user_id = 199
发往 MySQL ; - 应用层外挂载 MySQL 的代理,类似 ShardingSphere 这种,流程跟方案 2 类似,只是改写由外部中间件完成。
个人感觉方案 2 是个挺好的思路但是 Go 里面好像没有什么特别好用的中间件。
Golang Go语言中你们在项目中如何实现分表读写的?插件?手写?代理?
更多关于Golang Go语言中你们在项目中如何实现分表读写的?插件?手写?代理?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
存储层手动调不同的读写实例。稳健。
更多关于Golang Go语言中你们在项目中如何实现分表读写的?插件?手写?代理?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
如果可以的话, 让业务同学更专心写业务吧, 分表这种交给运维
如果没条件, 只能自己搞, 2 更好一些
我们也是这么做的,确实稳健,所有的流程都能在 debug 的时候看清楚,其实就是相当于嵌入业务了,能感知到,坏处在于多加几行代码,库表越多,写得越多
在理
直接上分布式的数据库
也是个解决方案
好奇分这么多表,列表查询怎么做的?
在 grom 上单写一个 table 方法, 接收相关分表参数, 返回一个 gorm.DB 对象, 然后每次都调用 table 方法获取对应 gorm.DB 对象就好了
类似于golang<br><br>func (d UserDao) table(userID int64) *gorm.DB {<br> return mysql.Client("user").Table(fmt.Sprintf("user_table_%d", userID%1000))<br>}<br><br>
分库:配置中心实现不同服务实例连不同的库
分表:程序中按规则拼表名
简单粗暴,但效果非常好。
一般有扫表的方案和异构存储 /离线数仓的方案;另外在决定分表之前也是需要考虑业务是否要频繁的批量查询,如果非常多批量操作的话,设计的时候要看能不能把分表依据和批量操作的依据结合起来,或者不用分表的方案实现
嗯嗯是个方案,我们现在也在用这样的写法
听播客,PingCAP 的 CTO 说他也遇到这种问题,然后就开发了 TiDB
一个用户的数据一般都在一个表内。跨用户查询的 case 比较少吧
mysql 的分区表,直接从数据库引擎层解决
咋扩容?如果后面扩展到了 999 个表。。。你这个 UserID 算出来的结果不一致了咋办。
gorm 好像有 db resolve 插件,这玩意自己写也比较方便吧
方案 2 吧 ShardingSphere 就是实现的这种;直接在 jdbc 层动手脚,跟 orm 框架无关;至于 go 这边就不清楚了;
或者直接上分布式数据库
前排求推荐开源的分布式 OLTP 数据库,大家用哪个比较多 ?
https://github.com/flike/kingshard 这个应该是你要找的解决方案虽然我没用过
2 、3 是一样吧 区别在于造轮子还是用现成的工具
最近看了一个帖子 “分库分表必死,分布式数据库必成主流” 意思就是分库分表以后会成为数据库产品自身特性而不是业务系统需要去考虑的
针对题主目前情况 还是建议用 2 灵活些
我们目前是直接分千表, 短期内用户不大量增长的话都够用了
如果需要频繁扩容的话确实不太好处理
没有比较成熟得,毕竟 go 生态摆在这,建议使用分布式数据库,或者使用云厂商服务比如 DRDS
其实 mysql 的分区表还是很好用的
分区字段 有个限制 必须主键
我们最开始用的 1
后面用的 2
之后改用 3
最后用了腾讯云上一款对标 TiDB 的产品
#14 水平分表,比如题主的 “例如 user_tab_00000000 - user_tab_00000199 ,一共 200 张表,按 user_id % 200 来分表。”
假设 id 递增,需要查询最近新增的 200 个用户,那不就是每一张表都要查询。
这种情况怎么处理的?
有历史原因的 Partition 有些场景不让使用(不管它是否好用,但是出于某些原因确实是不能使用)
resolver 只解决连不同 db 的问题吧,好像不是解决分表的问题的
Nice to hear. 不管好不好用,可以了解一下,感谢~
对了还有一个原因是因为有些 sharding 算法并不是简单的取余,也是因为业务的特殊原因,需要实现一些奇奇怪怪的内容进去,所以不能只依靠 partition
直接上 ShardingSphere
或者直接 yugabytedb ,sharding 非常容易,一个命令的事情。
这种类型的查询应该不会是 toC 量级的 qps 吧,如果次数不多就遍历呗,如果是相对高频(比如营销平台),那就搞离线数据库,汇总数据
一致性 hash😂
binlog 同步到 clickhouse 或者 es 直接查询,相当于用双倍的空间分别支撑 OLTP 和 OLTP 查询,如果能接受较长延迟 /执行耗时,或者说有超大批量查询要求的话应该转移到离线数仓去。
在Golang项目中实现分表读写,通常有几种常见的方法,包括使用插件、手写逻辑以及通过代理来实现。这些方法各有优缺点,具体选择需根据项目需求和团队技术栈来决定。
-
使用插件: 一些开源框架和插件提供了分表读写的功能,比如Sharding-JDBC(虽然主要用于Java,但类似思想可借鉴)。在Go语言中,可以尝试使用类似功能的ORM框架插件,如GORM的Sharding扩展,它们可以帮助简化分表逻辑的实现,但可能需要一定的定制工作来适应具体业务需求。
-
手写逻辑: 对于定制化需求较高的项目,手写分表逻辑是一个灵活的选择。通过解析SQL语句、识别表和条件,动态生成针对具体分表的查询或写入语句。这种方法需要对数据库操作有较深入的理解,且代码维护成本较高。
-
通过代理: 使用数据库中间件或代理层,如MyCAT、ShardingSphere(同样多用于Java生态,但原理相通),可以实现透明的分表操作。在Go应用中,只需配置连接到这些中间件,它们会负责处理分表逻辑。这种方法的好处是应用层无需改动,但可能引入额外的性能开销和运维复杂度。
综上所述,选择哪种方式取决于项目的具体需求、团队的技术栈以及对于性能和维护成本的权衡。在实际操作中,也可以结合多种方法,以达到最佳效果。