【问题标题】:How to Connect Golang application to mysql statefulset in Kubernetes如何将 Golang 应用程序连接到 Kubernetes 中的 mysql statefulset
【发布时间】:2022-01-27 14:16:59
【问题描述】:

我在https://kubernetes.io/docs/tasks/run-application/run-replicated-stateful-application/https://kubernetes.io/docs/tasks/run-application/run-replicated-stateful-application/ 处遵循了有关如何将 MySQL 部署为 statefulset 的官方演练

我已经启动并运行良好,但指南说:

名为 mysql-read 的客户端服务是一个普通的服务,它有自己的集群 IP,它在所有报告就绪的 MySQL Pod 之间分配连接。潜在端点集包括主 MySQL 服务器和所有副本。 请注意,只有读取查询才能使用负载平衡的客户端服务。因为只有一个主 MySQL 服务器,客户端应该直接连接到主 MySQL Pod(通过其在 Headless Service 中的 DNS 条目)来执行写入。

这是我的连接代码:

func NewMysqlClient() *sqlx.DB {

//username:password@protocol(address)/dbname?param=value
dataSourceName := fmt.Sprintf("%s:%s@tcp(%s)/%s?parseTime=true&multiStatements=true",
    username, password, host, schema,
)
log.Println(dataSourceName)
var mysqlClient *sqlx.DB
var err error
connected := false

log.Println("trying to connect to db")
for i:=0; i<7; i++{
    mysqlClient, err = sqlx.Connect("mysql", dataSourceName)
    if err == nil {
        connected = true
        break
    } else {
        log.Println(err)
        log.Println("failed will try again in 30 secs!")
        time.Sleep(30*time.Second)
    }
}

if (!connected){
    log.Println(err)
    log.Println("Couldn't connect to db will exit")
    os.Exit(1)
}

log.Println("database successfully configured")

return mysqlClient

}

当我将应用程序连接到无头 MySQL 服务时,我得到:

Error 1290: The MySQL server is running with the --super-read-only option so it cannot execute this statement"

我猜它正在连接到一个从属副本,当我连接到 mysql-0.mysql 主机时,一切正常,这是预期的主节点。

我的问题是,当我们只连接到主节点时,我的应用程序如何能够从从节点读取数据,因为应用程序需要能够写入数据。

我尝试使用mysql-0.mysql,mysql-1.mysql,mysql-2.mysql,但后来我得到:

dial tcp: lookup mysql-0.mysql;mysql-1.mysql,mysql-2.mysql: no such host

所以我想知道是否有办法将三个副本连接在一起,以便我们写入主副本并从任何其他数据库(如 mongo 等)中读取。 如果无法连接到所有副本,您会如何建议我从从属读取并写入主控。

谢谢!

【问题讨论】:

    标签: mysql go kubernetes minikube kubernetes-statefulset


    【解决方案1】:

    您必须使用 服务名称 从 Go 应用程序连接 MySQL

    所以你的流量像

    Go 应用程序 POD 在与容器内的 POD 相同的 K8s 集群中运行

    向 MySQL 服务发送请求 -> MySQL 服务将流量转发到 MySQL 状态集(POD 或其他合并副本中)

    因此,如果您在案例中创建了服务,则主机名将是服务名称:mysql

    例如你可以参考这个:https://kubernetes.io/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume/

    如果您注意到 WordPress 如何连接到 mysql

    containers:
          - image: wordpress:4.8-apache
            name: wordpress
            env:
            - name: WORDPRESS_DB_HOST
              value: wordpress-mysql
    

    它使用 MySQL 服务名称wordpress-mysql 作为主机名进行连接。

    如果你只是想连接 Read Replica 你可以使用服务名mysql-read

    你也可以尝试连接

    kubectl run mysql-client --image=mysql:5.7 -i --rm --restart=Never --\ mysql -h mysql-0.mysql

    选项-2

    如果您只是连接特定的 POD 或编写副本,您可以使用

    &lt;pod-name&gt;.mysql

    Headless Service 为 DNS 条目提供了一个归属地, StatefulSet 控制器为属于该集合的每个 Pod 创建。 因为 Headless Service 被命名为 mysql,所以 Pod 是可以访问的 通过从同一 Pod 中的任何其他 Pod 中解析 .mysql Kubernetes 集群和命名空间。

    【讨论】:

    • 嗨!感谢您抽出时间回复!是的,我确实使用了您标记为选项 1 的内容,并且当我有一个有状态 pod 时它运行良好,但现在我使用 statefulset 它没有,我收到一个错误,说我在连接时以只读方式连接使用指南中指定的无头服务名称。正如您在选项 2 中建议的那样,当我使用 mysql-0.mysql 时,一切正常,但这意味着我只连接到主服务器而不使用其他两个从服务器!我弄错了吗?
    • 你的理解是对的。当您连接特定副本时,您将能够执行写入或读取操作。 mysql-0.mysql 是这里的主人,所以如果你想在代码中使用只读副本,你必须使用 mysql-1.mysqlmysql-2.mysql
    • 我不确定当任何 pod 崩溃时 MySQL 的行为是否会自动更改主副本。使用 Redis 数据库,如果一个 pod 崩溃,Master 会更改为 2 号副本。因此您需要在使用 fix mysql-0.mysql for just write 和 mysql-1.mysql just read 之前检查这种情况。
    • 我明白你的意思!但是当我尝试在连接字符串中提及多个副本时,DNS 查找失败,如果我连接 ti mysql-1.mysql 那么我将无法写入数据!如果我让两个客户端连接到主控另一个从属它会在代码中非常混乱我觉得有时使用一个客户端然后另一个,你同意吗?
    • 是的,您在这方面是绝对正确的。这是一种方式。我再次很抱歉不确定 MySQL,但在 Redis 中有一个称为哨兵的概念,它的作用是返回每个可用副本的 IP 以及写入和读取 IP。当您点击它时将其视为应用程序返回主从 IP,您可以通过方法进一步使用它。示例:github.com/redis/redis-py#sentinel-support
    【解决方案2】:

    另一种适当的方法可能是您的应用程序代码忽略主实例、副本实例等,并像连接到单个主实例一样运行,并且在有能力的代理中抽象了读、写查询拆分。该代理负责将写入查询路由到主实例并将读取查询路由到副本实例。 示例代理 - https://proxysql.com/

    【讨论】:

      猜你喜欢
      • 2020-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多