go 和数据库

2023年 8月 13日 45.2k 0

go和数据库

经典案例

数据产生

如一个注册新帐号的操作

数据流动

一条用户注册数据 -> 后端服务器 -> 数据库系统 -> 其他非存储系统

数据持久化

数据到达数据库系统

  • 检验数据合法性
  • 修改内存,用高效数据结构组织数据
  • 写入存储介质
  • 潜在问题

  • 数据丢失
  • 多人并发修改数据
  • 为什么用数据库
  • 只能处理结构化数据吗
  • 有什么操作数据库的方式?要用什么编程语言
  • 存储 & 数据库系统

    存储系统:一个提供读写,控制类接口,能安全有效把数据持久化的软件,即存储系统

    用户,硬盘,内存,网络

    存储系统特点

  • 作为后端软件底座,性能敏感,性能必须优化到极致
  • 容易受硬件影响,要考虑到硬件变革
  • 代码在IO路径上要简单,在错误处理,日志,监控,配置等方面要复杂
  • 存储器层级结构

    Persistent Memory, 近年来出现的新技术,介于内存和SSD之间,速度比SSD快,容量比内存大

    数据从应用到存储介质

    缓存很重要,贯穿整个存储体系

    拷贝很昂贵,尽量减少

    硬件设备五花八门,需要有抽象统一的接入层

    RAID 技术

    单机存储系统如何高性能,高可靠,高性价比

    RAID:Redundant Array of Inexpensive Disks

    RAID 背景

    • 单块大容量磁盘价格大于多块小容量磁盘价格
    • 单块磁盘写入性能小于多块磁盘并发写入
    • 单块磁盘容错能力有限,不够安全

    RAID 0

    多块磁盘简单组合,数据条带化,提升磁盘带宽,没有容错能力

    RAID 1

    一块磁盘对应一块镜像磁盘,真实空间利用率50%,有容错能力

    RAID 0+1

    结合 RAID 0 和 RAID 1,数据条带化,镜像备份,有容错能力

    数据库

    关系模型

    关系 = 集合 = 任意元素的若干有序偶对,反应现实世界的实体和实体之间的联系

    关系代数 = 对关系做运算的抽象查询语言

    SQL = 结构化查询语言,关系代数的具体实现

    关系型数据库

    关系型数据库是存储系统,但除此之外还有其他能力

    • 结构化数据友好
    • 支持事务处理
    • 支持SQL

    非关系型数据库

    非关系型不要求严格结构化

    • 半结构化数据友好
    • 可能支持事务处理
    • 可能支持SQL

    数据库 vs 存储系统

    数据库:写入关系型数据库,以表的形式存储,读取时需要解析,转换成内存中的数据结构

    存储系统:写入文件,自行定义,管理结构

    事务能力

    ACID:原子性,一致性,隔离性,持久性

    • A:原子性,事务中的所有操作要么全部成功,要么全部失败
    • C:一致性,事务执行前后,数据库都必须处于一致状态
    • I:隔离性,事务执行过程中,对外部数据的修改,对其他事务是不可见的
    • D:持久性,事务执行成功后,对数据的修改是永久的

    主流产品剖析

    单机存储

    单个计算机节点上的存储软件系统,不涉及网络交互

    文件系统

    Linux 经典哲学:一切皆文件

    文件系统管理单元:文件

    Linux 文件系统两大数据结构,inode 和 dentry

    inode:索引节点,记录文件的元数据,如文件大小,创建时间,修改时间,访问时间,权限,文件指针,会被存储到磁盘上,总数在格式化文件系统时就固定了
    dentry:目录项,记录文件名和inode的对应关系,是内存结构,和inode的关系是多对一(hardlink)

    key-value 存储系统

    key-value 存储系统:把数据按照 key-value 的形式存储,key 和 value 都是二进制数据,value 可以是结构化数据,也可以是非结构化数据

    常见使用方式:put(key, value), get(key), delete(key)

    常见数据结构:LSM 树,牺牲读取性能,换取写入性能

    拳头产品:RocksDB

    分布式存储

    分布式存储系统:多个计算机节点上的存储软件系统,涉及网络交互

    分布式文件系统

    HDFS:Hadoop Distributed File System

    大数据时代的基石

    专用高级硬件很贵,数据存量也很大,要求超高吞吐

    核心特点:

    • 支持海量数据存储
    • 高容错性
    • 弱POSIX语义
    • 使用普通x86服务器,性价比高

    Ceph

    开源分布式存储系统的万金油

    核心特点:

    • 一切皆对象,支持对象接口,块接口,文件接口
    • 数据写入采用主从复制
    • 数据分布使用 CRUSH 算法

    单机数据库

    单机数据库:单个计算机节点上的数据库软件系统,不涉及网络交互

    关系型数据库概览

    商业产品:Oracle,DB2,SQL Server

    开源产品:MySQL,PostgreSQL

    关系型数据库通用组件:

    • Query Engine:SQL解析,优化,执行
    • Txn Manager:事务并发控制
    • Storage Engine:数据存储和索引
    • Lock Manager:锁管理
    • Replication:主从复制

    关键内存数据结构:

    • B-Tree:索引,支持范围查询
    • B+Tree:索引,支持范围查询,支持顺序访问
    • LRU:缓存,支持淘汰

    磁盘数据结构:

    • WriteAheadLog:预写式日志,支持事务
    • Page:数据页,支持随机访问

    非关系型数据库概览

    MongoDB, Redis, Elasticsearch 三足鼎立

    • 交互方式各不相同
    • schema相对灵活
    • 尝试去支持SQL

    Elaticsearch:全文搜索引擎,基于Lucene,支持分布式,支持SQL,面向文档存储,可序列化为JSON, 实现大量搜索数据结构和算法

    mongoDB:面向文档存储,可序列化为JSON,支持SQL,存在 collection, 为文档的集合,支持食物,由SDK支持交互可通过插件支持 SQL

    Redis:面向键值存储,支持多种数据结构,主要基于内存,但也可以进行持久化,常用 redis-cli/多语言SDK 交互

    分布式数据库

    解决容量问题

    单体数据库系统单点容量有限,受硬件限制

    分布式数据库:存储节点池化,动态扩缩容

    解决弹性问题

    单体数据库升级扩容,需要停机,影响业务

    分布式数据库:存储节点和CPU池化,动态扩缩容

    问题

    单写多写

    从磁盘弹性到内存弹性

    分布式事务优化

    新技术演进

    软件架构变更

    Bypass OS kernel:绕过操作系统内核,直接访问硬件

    SPDK:Storage Performance Development Kit

  • 通过用户态驱动程序,绕过操作系统内核,直接访问硬件
  • 用轮询代替中断
  • 无锁化设计,降低开销
  • AI

    数据存储格式转换

    新硬件革命

  • RDMA:Remote Direct Memory Access,远程直接内存访问,绕过操作系统内核,直接访问内存
  • Persistent Memory:持久内存,介于内存和SSD之间,速度比SSD快,容量比内存大
  • 可编程交换机:P4,可编程数据包处理器,可编程交换机,可编程网卡,可编程存储控制器
  • CPU/GPU/DPU:越来越强的计算能力(DPU:异构计算,减轻CPU负担)
  • gorm

    迭代十年的ORM框架,支持主流数据库,支持事务,支持连接池,支持链式操作,支持预加载,支持事务

    gorm 基础使用

  • 定义 gorm model 结构体
  • 为 model 定义表名
  • 连接数据库
  • 增删查改
  • gorm 使用驱动连接数据库,支持主流数据库,如 mysql,postgres,sqlite,sqlserver,oracle

    创建数据

    // 创建数据
    db.Create(&User{Name: "Jinzhu", Age: 18, Birthday: time.Now()})
    

    如何使用 Upsert,使用OnConflict处理数据冲突

    // Upsert
    db.Clauses(clause.OnConflict{DoNothing: true}).Create(&user)
    

    如何使用默认值

    // 默认值
    type User struct {
      gorm.Model
      Name         string `gorm:"default:'noname'"`
      Age          int64
    }
    

    查询数据

    // 查询数据
    var user User
    db.First(&user, 1) // 查询id为1的product
    db.First(&user, "name = ?", "jinzhu") // 查询code为l1212的product
    

    First 使用踩坑:查询不到数据时返回 ErrRecordNotFound 错误,查询多条数据不会返回错误

    使用结构体为查询条件:指挥查询非零值字段,可以使用map构建查询条件

    更新数据

    // 更新数据
    db.Model(&user).Update("name", "jinzhu")
    
    // 更新多个字段
    db.Model(&user).Updates(User{Name: "jinzhu", Age: 18}) // 仅更新非零值字段
    
    // 使用map更新多个字段
    db.Model(&user).Updates(map[string]interface{}{"name": "jinzhu", "age": 18})
    
    // 更新选定字段
    db.Model(&user).Select("name").Updates(map[string]interface{}{"name": "jinzhu", "age": 18})
    
    // gorm 表达式
    db.Model(&user).Select("age").Updates(map[string]interface{}{"age": gorm.Expr("age * ? + ?", 2, 100)})
    

    删除数据

    // 物理删除
    db.Delete(&user)
    
    // 软删除
    type User struct {
      gorm.Model
      Name         string
      Age          int64
      DeletedAt    gorm.DeletedAt
    }
    
    db.Delete(&user)
    

    被软删除的数据不会被查询到,会将DeletedAt置为当前时间,可以使用 Unscoped 方法查询到

    gorm 事务

    Gorm 使用了 Begin 方法开启事务,使用 Commit 方法提交事务,使用 Rollback 方法回滚事务

    // 开启事务
    tx := db.Begin()
    // 事务操作
    tx.Create(...)
    tx.Update(...)
    tx.Delete(...)
    // 回滚事务
    tx.Rollback()
    // 提交事务
    tx.Commit()
    
    // 自动提交事务
    var err Error
    tx := db.Begin()
    tx.Create(...)
    if err = tx.Transaction(func(tx *gorm.DB) error {
      tx.Update(...)
      tx.Delete(...)
      return nil
    }); err != nil {
      tx.Rollback()
    }
    

    gorm hook

    gorm 提供了 hook 方法,可以在创建、更新、删除、查询时执行自定义的方法, 且可以在 hook 方法中返回错误,自动回滚

    // 创建前
    func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
      u.ID = uuid.New().String()
      return
    }
    

    性能提高

    对于写操作,为了确保数据完整性,gorm 会将他们封装事务内运行,可以使用skipDefaultTransaction 关闭

    使用 PrepareStmt 预编译 SQL 语句

    相关文章

    服务器端口转发,带你了解服务器端口转发
    服务器开放端口,服务器开放端口的步骤
    产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
    如何使用 WinGet 下载 Microsoft Store 应用
    百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
    百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

    发布评论