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

本文涉及的产品
云原生网关 MSE Higress,422元/月
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
注册配置 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
相关文章
|
Java Go 开发者
100天精通Golang(基础入门篇)——第15天:深入解析Go语言中函数的应用:从基础到进阶,助您精通函数编程!(进阶)
100天精通Golang(基础入门篇)——第15天:深入解析Go语言中函数的应用:从基础到进阶,助您精通函数编程!(进阶)
76 0
|
SQL 测试技术 Go
Golang实用进阶工具
Golang实用进阶工具
62 0
|
缓存 安全 Go
Golang 进阶文章一览
Golang 进阶文章一览
109 0
|
中间件 关系型数据库 MySQL
Golang进阶,揉碎数据库中间件,干货满满!(一)
Golang进阶,揉碎数据库中间件,干货满满!(一)
216 3
Golang进阶,揉碎数据库中间件,干货满满!(一)
|
SQL 中间件 关系型数据库
Golang进阶,揉碎数据库中间件,干货满满!(二)
Golang进阶,揉碎数据库中间件,干货满满!(二)
306 3
Golang进阶,揉碎数据库中间件,干货满满!(二)
|
2月前
|
Go
Golang语言之管道channel快速入门篇
这篇文章是关于Go语言中管道(channel)的快速入门教程,涵盖了管道的基本使用、有缓冲和无缓冲管道的区别、管道的关闭、遍历、协程和管道的协同工作、单向通道的使用以及select多路复用的详细案例和解释。
110 4
Golang语言之管道channel快速入门篇
|
2月前
|
Go
Golang语言文件操作快速入门篇
这篇文章是关于Go语言文件操作快速入门的教程,涵盖了文件的读取、写入、复制操作以及使用标准库中的ioutil、bufio、os等包进行文件操作的详细案例。
64 4
Golang语言文件操作快速入门篇
|
2月前
|
Go
Golang语言之gRPC程序设计示例
这篇文章是关于Golang语言使用gRPC进行程序设计的详细教程,涵盖了RPC协议的介绍、gRPC环境的搭建、Protocol Buffers的使用、gRPC服务的编写和通信示例。
101 3
Golang语言之gRPC程序设计示例
|
2月前
|
安全 Go
Golang语言goroutine协程并发安全及锁机制
这篇文章是关于Go语言中多协程操作同一数据问题、互斥锁Mutex和读写互斥锁RWMutex的详细介绍及使用案例,涵盖了如何使用这些同步原语来解决并发访问共享资源时的数据安全问题。
86 4
|
2月前
|
Go 调度
Golang语言goroutine协程篇
这篇文章是关于Go语言goroutine协程的详细教程,涵盖了并发编程的常见术语、goroutine的创建和调度、使用sync.WaitGroup控制协程退出以及如何通过GOMAXPROCS设置程序并发时占用的CPU逻辑核心数。
50 4
Golang语言goroutine协程篇