Golang进阶,揉碎数据库中间件,干货满满!(二)

本文涉及的产品
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
云原生网关 MSE Higress,422元/月
注册配置 MSE Nacos/ZooKeeper,118元/月
简介: Golang进阶,揉碎数据库中间件,干货满满!(二)

七、权限管理实现原理#


重点关注的地方:


# server.go:381
// todo 用户白名单校验,只有指定的user、ip才能使用Proxy
if allowConnect := conn.IsAllowConnect(); allowConnect == false {
    err := mysql.NewError(mysql.ER_ACCESS_DENIED_ERROR, "ip address access denied by kingshard.")
    conn.writeError(err)
    conn.Close()
    return
  }


视频地址:https://www.bilibili.com/video/BV19g411N7NR?p=7


八、MySQL协议-Handshake!和中间件握手机制原理#


原理图:



重点关注的地方:


server.go:388


// todo 基于MySQL协议和客户端建立握手机制
  if err := conn.Handshake(); err != nil {
    golog.Error("server", "onConn", err.Error(), 0)
    conn.writeError(err)
    conn.Close()
    return
  }


backend_conn.go:101


// todo 这里其实Proxy和MySQL Server之间建立连接的逻辑
  // todo 大家看到这里不明白也没关系,因为想看懂这里需要了解MySQL协议,后面的视频中我会跟大家讲明白这件事
  // todo 大家只需要知道,执行过这里的代码之后呢,proxy和MySQL-Service之间就会建立一个Conn,
  // todo 并且Proxy会维护这个Conn,后续用户的SQL打过来之后,Proxy会将用户的SQL转发给这里获取到的Conn,进尔让MySQL的引擎去真正的执行这里的SQL
  // todo 读MySQL发过来的握手报文
  if err := c.readInitialHandshake(); err != nil {
    c.conn.Close()
    return err
  }
  // todo 写自己的信息(port、username、password、host)
  if err := c.writeAuthHandshake(); err != nil {
    c.conn.Close()
    return err
  }
  // todo 读取MySQL-Server发过来的ok报文
  if _, err := c.readOK(); err != nil {
    c.conn.Close()
    return err
  }


视频地址:https://www.bilibili.com/video/BV19g411N7NR?p=8


九、中间件不断接受处理客户端SQL原理#


重点关注的地方:

conn.go:279


// todo 下面的代码在一个无限循环中, 不断的接受客户端发送过来的sql语句
  for {
    // todo 根据MySQL协议解析数据包,获取出数据包中sql语句
    data, err := c.readPacket()
    if err != nil {
      return
    }
    if c.configVer != c.proxy.configVer {
      err := c.reloadConfig()
      if nil != err {
        golog.Error("ClientConn", "Run",
          err.Error(), c.connectionId,
        )
        c.writeError(err)
        return
      }
      c.configVer = c.proxy.configVer
      golog.Debug("ClientConn", "Run",
        fmt.Sprintf("config reload ok, ver:%d", c.configVer), c.connectionId,
      )
    }
    // 使用dispatch方法,继续处理数据包
      if err := c.dispatch(data); err != nil {
      c.proxy.counter.IncrErrLogTotal()
      golog.Error("ClientConn", "Run",
        err.Error(), c.connectionId,
      )
      c.writeError(err)
      if err == mysql.ErrBadConn {
        c.Close()
      }
    }
    if c.closed {
      return
    }
    c.pkg.Sequence = 0
  }
}


视频地址:https://www.bilibili.com/video/BV19g411N7NR?p=9


十、中间件是如何执行你的select语句的?#


重点关注的地方:

conn.go:279


// 使用dispatch方法,继续处理数据包
      if err := c.dispatch(data); err != nil {
      c.proxy.counter.IncrErrLogTotal()
      golog.Error("ClientConn", "Run",
        err.Error(), c.connectionId,
      )
      c.writeError(err)
      if err == mysql.ErrBadConn {
        c.Close()
      }
    }


conn.go:340


func (c *ClientConn) dispatch(data []byte) error {
  c.proxy.counter.IncrClientQPS()
  // todo MYSQL协议规定了,客户端发送过来的数据格式是:cmd+data
  // todo 其中的cmd就是sql的类型,类型都枚举在下面了,打眼一看都能懂
  cmd := data[0]
  // todo data部分就是sql详细内容
  data = data[1:]
  switch cmd {
  case mysql.COM_QUIT:
    c.handleRollback()
    c.Close()
    return nil
  case mysql.COM_QUERY: // todo select 语句
    return c.handleQuery(hack.String(data))
  case mysql.COM_PING: // todo ping 语句
    return c.writeOK(nil)
  case mysql.COM_INIT_DB:
    return c.handleUseDB(hack.String(data))
  case mysql.COM_FIELD_LIST:
    return c.handleFieldList(data)
  case mysql.COM_STMT_PREPARE:
    return c.handleStmtPrepare(hack.String(data))
  case mysql.COM_STMT_EXECUTE:// todo insert、update 语句
    return c.handleStmtExecute(data)
  case mysql.COM_STMT_CLOSE:
    return c.handleStmtClose(data)
  case mysql.COM_STMT_SEND_LONG_DATA:
    return c.handleStmtSendLongData(data)
  case mysql.COM_STMT_RESET:
    return c.handleStmtReset(data)
  case mysql.COM_SET_OPTION:
    return c.writeEOF(0)
  default:
    msg := fmt.Sprintf("command %d not supported now", cmd)
    golog.Error("ClientConn", "dispatch", msg, 0)
    return mysql.NewError(mysql.ER_UNKNOWN_ERROR, msg)
  }
  return nil
}


视频地址:https://www.bilibili.com/video/BV19g411N7NR?p=10


十一、读写分离实现原理#


重点关注的地方:


conn_pershard.go:97


// todo 从选出DB中获取一条可用的连接,如果是没有开事物且是读请求的话,executeDB.IsSlave一般为true
  conn, err := c.getBackendConn(executeDB.ExecNode, executeDB.IsSlave)
  defer c.closeConn(conn, false)
  if err != nil {
    return false, err
  }


视频地址:https://www.bilibili.com/video/BV19g411N7NR?p=11

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
6月前
|
SQL 关系型数据库 MySQL
探索Gorm - Golang流行的数据库ORM框架
探索Gorm - Golang流行的数据库ORM框架
|
5月前
|
缓存 负载均衡 监控
探秘数据库中间件:ProxySQL与MaxScale的优势与劣势
探秘数据库中间件:ProxySQL与MaxScale的优势与劣势
193 2
|
3月前
|
运维 安全 Cloud Native
核心系统转型问题之分布式数据库和数据访问中间件协作如何解决
核心系统转型问题之分布式数据库和数据访问中间件协作如何解决
|
5月前
|
缓存 NoSQL 中间件
应对数据库不断膨胀的数据:缓存和队列中间件
【6月更文挑战第5天】该文探讨了优化数据库使用以提升应用系统性能的策略。文中建议利用Redis缓存和MQ消息队列作为辅助工具,以进一步优化性能和减少资源消耗。
144 2
应对数据库不断膨胀的数据:缓存和队列中间件
|
4月前
|
中间件 Java 测试技术
单元测试问题之编写单元测试时运行环境、数据库、中间件问题如何解决
单元测试问题之编写单元测试时运行环境、数据库、中间件问题如何解决
|
5月前
|
SQL 关系型数据库 MySQL
mysqldiff - Golang 针对 MySQL 数据库表结构的差异 SQL 工具
Golang 针对 MySQL 数据库表结构的差异 SQL 工具。https://github.com/camry/mysqldiff
92 7
|
4月前
|
SQL 中间件 关系型数据库
MyCAT数据库中间件的架构与使用方法
MyCAT数据库中间件的架构与使用方法
|
6月前
|
缓存 监控 中间件
中间件Cache-Aside策略应用程序直接与缓存和数据库进行交互
【5月更文挑战第8天】中间件Cache-Aside策略应用程序直接与缓存和数据库进行交互
82 4
|
6月前
|
SQL 关系型数据库 MySQL
Golang数据库编程详解 | 深入浅出Go语言原生数据库编程
Golang数据库编程详解 | 深入浅出Go语言原生数据库编程
|
6月前
|
JavaScript 前端开发 中间件
Node.js—Express使用、Express 路由 、Express 中间件、托管静态资源、使用 Express 写接口、node.js链接sqlite数据库
Node.js—Express使用、Express 路由 、Express 中间件、托管静态资源、使用 Express 写接口、node.js链接sqlite数据库
230 0