docker-compose和traefik实现本机PXC集群的快速搭建和负载均衡
什么是PXC?
Percona XtraDB Cluster (PXC) 是一个完全开源的 MySQL 数据库集群解决方案,它可确保高可用性,防止停机和数据丢失,并为不断增长的环境提供线性可扩展性。它将 Percona Server 和 Percona XtraBackup 与 Galera 库集成在一起,以实现同步多源复制。
PXC有哪些作用
- 同步复制:PXC使用Galera Cluster的同步复制技术,保证在所有节点之间的数据一致性。当一个节点接收到一个事务时,它提示事务复制到其他节点,从而实现数据的同步复制。
- 故障检测和自动故障转移:PXC具备故障检测和自动故障转移机制作。当一个节点宜机或不可用时,群会检测到并自动将请求路由到其他可用节点,以确保系统的可用性能。
- 读写负载均衡:由于PXC的多主复制架构众多,应用程序可以同时在节点上进行读和写操作,从而实现读写负载均值衡。
- 数据一致性和事务支持:PXC确保在整个维护集群中的所有节点之间的数据一致性,并提供完全支持ACID特性的事务处理。
PXC是一个强大的MySQL集群解决方案,可以提供高可用性、容错性和可扩展性。
PXC模式和Replication(传统主从)对比
- 写操作延迟:PXC模式通常具有较低的写操作延迟,因为所有节点都可以处理写操作。而传统主从复制模式的写操作延迟较高,因为写操作必须由主节点处理并传播到从节点。
- 扩展性:PXC模式支持水平扩展,可以通过添加更多节点来增加集群的容量和性能。传统主从复制模式则需要在主节点上进行垂直扩展,增加其处理能力。
- 数据一致性:PXC模式通过多数派投票来实现数据一致性,并且在网络分区或节点故障时能够自动处理。传统主从复制模式在进行故障切换时可能会有一些数据丢失,需要手动处理数据一致性。
- 可用性:PXC模式在集群中的任何节点出现故障时都能保持可用性,因为所有节点都可以处理读写操作。传统主从复制模式在主节点故障时需要进行故障切换,可能会导致一段时间内的服务中断。
Traefik
Traefik 是一种流行的开源反向代理和负载均衡器,广泛用于容器化环境。它提供了多种优势和功能,使其成为管理传入流量并将其路由到微服务或应用程序的热门选择。以下是常用Traefik的一些原因:
- 动态配置:Traefik 提供动态服务的配置和发现。它与 Docker、Kubernetes 和 Swarm 等容器编排器无缝集成,并且可以在部署或删除新服务时自动检测它们。这种动态配置消除了手动更新的需要,并使扩展和管理基础结构变得更加容易。
- 负载平衡:Traefik 提供内置的负载平衡功能。它将传入流量分布到应用程序或服务的多个实例之间,从而提高整体性能、可伸缩性和可靠性。Traefik 支持各种负载平衡算法,包括轮询、最少连接和 IP 哈希。
- **自动 SSL/TLS:**Traefik 简化了 SSL/TLS 证书的管理。它可以为您的服务自动获取和续订Let’s Encrypt SSL证书,确保客户端和服务器之间的安全通信,而无需手动证书管理。此功能可节省保护应用程序的时间和精力。
- 流量路由和中间件:Traefik 提供强大的流量路由功能,并支持基于主机、路径、标头等请求属性的各种路由规则。它还支持中间件,允许您向服务添加其他功能,如身份验证、速率限制、请求重写等。这种灵活性使您能够自定义和控制流量以满足您的特定要求。
- 监控和指标:Traefik 提供内置的监控和指标功能。它提供了一个基于 Web 的仪表板和一个 API,用于监视服务的运行状况和性能。此外,Traefik 可以与流行的监控系统(如 Prometheus、InfluxDB 和 Grafana)集成,使您能够收集和可视化有关基础架构的详细指标。
- 社区和生态系统:Traefik 拥有一个庞大而活跃的用户和贡献者社区。这是一个不断发展和改进的开源项目。社区提供支持、文档以及众多插件和扩展,以增强 Traefik 的功能并与其他工具集成。
快速开始
#拉取pxc镜像
docker pull percona/percona-xtradb-cluster:5.7.34-31.51
#此次指定版本,8.0后需要配置证书
新建docker-compose.yaml,这里我们选择traefik进行pxc集群的负载均衡,3306为统一的调用端口
version : '3.7'
networks:
traefik-pxc:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.16.238.0/24
services:
traefik:
image: traefik:v2.4
command:
- "--providers.docker=true"
- "--entrypoints.pxc.address=:3301"
- "--api=true" # 启用Traefik的API
- "--api.insecure=true"# 启用Traefik的Web UI
- "--providers.docker"
ports:
- "8080:8080" # Traefik dashboard
- "3301:3301"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
networks:
- traefik-pxc
db1:
container_name: db1
image: percona/percona-xtradb-cluster:5.7.34-31.51
privileged: true
networks:
traefik-pxc:
ipv4_address: 172.16.238.9
ports:
- "30001:3306"
environment:
- "CLUSTER_NAME=JWSPXC"
- "XTRABACKUP_PASSWORD=db123456"
- "MYSQL_ROOT_PASSWORD=db123456"
- "TZ=Asia/Shanghai"
volumes:
- ./data/v1/data:/var/lib/mysql
- ./data/v1/backup:/data
labels:
- "traefik.enable=true"
- "traefik.tcp.routers.pxc-cluster.rule=HostSNI(`*`)"
- "traefik.tcp.routers.pxc-cluster.entrypoints=pxc"
- "traefik.tcp.services.pxc-cluster.loadbalancer.server.port=3306"
db2:
container_name: db2
image: percona/percona-xtradb-cluster:5.7.34-31.51
privileged: true
networks:
traefik-pxc:
ipv4_address: 172.16.238.3
environment:
- "CLUSTER_NAME=JWSPXC"
- "XTRABACKUP_PASSWORD=db123456"
- "TZ=Asia/Shanghai"
- "CLUSTER_JOIN=db1"
ports:
- "30002:3306"
volumes:
- ./data/v2/data:/var/lib/mysql
- ./data/v2/backup:/data
depends_on:
- db1
labels:
- "traefik.enable=true"
- "traefik.tcp.routers.pxc-cluster.rule=HostSNI(`*`)"
- "traefik.tcp.routers.pxc-cluster.entrypoints=pxc"
- "traefik.tcp.services.pxc-cluster.loadbalancer.server.port=3306"
db3:
container_name: db3
image: percona/percona-xtradb-cluster:5.7.34-31.51
privileged: true
networks:
traefik-pxc:
ipv4_address: 172.16.238.4
environment:
- "CLUSTER_NAME=JWSPXC"
- "XTRABACKUP_PASSWORD=db123456"
- "TZ=Asia/Shanghai"
- "CLUSTER_JOIN=db1"
ports:
- "30003:3306"
volumes:
- ./data/v3/data:/var/lib/mysql
- ./data/v3/backup:/data
depends_on:
- db1
labels:
- "traefik.enable=true"
- "traefik.tcp.routers.pxc-cluster.rule=HostSNI(`*`)"
- "traefik.tcp.routers.pxc-cluster.entrypoints=pxc"
- "traefik.tcp.services.pxc-cluster.loadbalancer.server.port=3306"
db4:
container_name: db4
image: percona/percona-xtradb-cluster:5.7.34-31.51
privileged: true
networks:
traefik-pxc:
ipv4_address: 172.16.238.5
environment:
- "CLUSTER_NAME=JWSPXC"
- "XTRABACKUP_PASSWORD=db123456"
- "TZ=Asia/Shanghai"
- "CLUSTER_JOIN=db1"
ports:
- "30004:3306"
volumes:
- ./data/v4/data:/var/lib/mysql
- ./data/v4/backup:/data
depends_on:
- db1
labels:
- "traefik.enable=true"
- "traefik.tcp.routers.pxc-cluster.rule=HostSNI(`*`)"
- "traefik.tcp.routers.pxc-cluster.entrypoints=pxc"
- "traefik.tcp.services.pxc-cluster.loadbalancer.server.port=3306"
db5:
container_name: db5
image: percona/percona-xtradb-cluster:5.7.34-31.51
privileged: true
networks:
traefik-pxc:
ipv4_address: 172.16.238.6
environment:
- "CLUSTER_NAME=JWSPXC"
- "XTRABACKUP_PASSWORD=db123456"
- "TZ=Asia/Shanghai"
- "CLUSTER_JOIN=db1"
ports:
- "30005:3306"
volumes:
- ./data/v5/data:/var/lib/mysql
- ./data/v5/backup:/data
depends_on:
- db1
labels:
- "traefik.enable=true"
- "traefik.tcp.routers.pxc-cluster.rule=HostSNI(`*`)"
- "traefik.tcp.routers.pxc-cluster.entrypoints=pxc"
- "traefik.tcp.services.pxc-cluster.loadbalancer.server.port=3306"
启动traefik
先启动traefik
docker-copmose up -d traefik
启动pxc集群
再启动db1
docker-compose up -d db1
注意:第一个节点启动比较慢,需要等待1分钟时间,可以使用数据据连接工具连接成功后再启动接下来的节点,这里你可以直接连映射的30001端口。
然后我们再去traefik的UI界面8080端口,注意MySQL 连接通常使用 TCP/IP 进行通信,这里我们暴露的统一负载均衡端口为3301,有不了解traefik的同学,可以官方文档里面看一下,个人感觉还是很好上手的,要是只想了解docker的使用,可以看https://doc.traefik.io/traefik/routing/providers/docker/。
发现traefik已经负载成功,接着我们依次启动下面的节点
docker-compose up -d db2
docker-compose up -d db3
docker-compose up -d db4
docker-compose up -d db5
五个节点负载均衡成功
可以看到啊,我们在30001端口的节点创建gopan库,其他节点也同步了,接下来我们写个test再测试一下:
package test
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
"testing"
)
func TestName(t *testing.T) {
// 数据库连接参数
dbHost := "localhost"
dbPort := 3301
dbUser := "root"
dbPassword := "db123456"
dbName := "gopan"
// 构建连接字符串
dataSourceName := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", dbUser, dbPassword, dbHost, dbPort, dbName)
// 连接到数据库
db, err := sql.Open("mysql", dataSourceName)
if err != nil {
fmt.Println("Failed to connect to database:", err)
return
}
defer db.Close()
// 测试连接
err = db.Ping()
if err != nil {
fmt.Println("Failed to ping database:", err)
return
}
fmt.Println("Connected to database successfully!")
// 进行数据库操作...
}
大功告成!😀😀😀😀😀😀😀
感谢
创作不易,博主花了整整一天弄这个😭😭😭😭😭😭,求求大家给个点赞关注吧!🥺
参考
Docker 通过PXC+Nginx实现高可用强一致性的mysql集群(单机多节点)