Skip to content

Commit c1b7b50

Browse files
committed
Add MySQL topology server implementation
Adds a MySQL-based topology backend (mysqltopo) for Vitess, allowing MySQL to be used as the topology store instead of etcd/zk/consul. This is useful in environments where MySQL is already available and adding etcd/zk would increase operational complexity. New files: - go/vt/topo/mysqltopo/ - Full topo.Factory implementation using MySQL including server, elections, locking, watches, and notifications - Plugin registrations for vtctld, vtgate, vttablet, vtorc, topo2topo, and vtctldclient - Example scripts for local development with MySQL topo Modified files: - go/vt/topo/server.go - Reuse global connection for cells when the factory supports HasGlobalReadOnlyCell (shared DB backends) - go/flags/endtoend/*.txt - Register --topo-mysql-election-ttl and --topo-mysql-lock-ttl flags - .github/workflows/local_example.yml - Add mysql to CI matrix Based on vitess v23.0.3.
1 parent 0466df5 commit c1b7b50

File tree

29 files changed

+7562
-3
lines changed

29 files changed

+7562
-3
lines changed

.github/workflows/local_example.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
runs-on: oracle-vm-16cpu-64gb-x86-64
2121
strategy:
2222
matrix:
23-
topo: [etcd,zk2]
23+
topo: [etcd,zk2,mysql]
2424

2525
steps:
2626
- name: Skip CI

examples/common/env.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ elif [ "${TOPO}" = "consul" ]; then
6565
#TODO: Remove underscore(_) flags in v25, replace them with dashed(-) notation
6666
TOPOLOGY_FLAGS="--topo-implementation consul --topo-global-server-address ${CONSUL_SERVER}:${CONSUL_HTTP_PORT} --topo-global-root vitess/global/"
6767
mkdir -p "${VTDATAROOT}/consul"
68+
elif [ "${TOPO}" = "mysql" ]; then
69+
# The MySQL topo addr is a valid go DSN
70+
MYSQL_TOPO_ADDR="topouser:topopass@tcp(127.0.0.1:3306)/topo"
71+
TOPOLOGY_FLAGS="--topo_implementation mysql --topo_global_server_address $MYSQL_TOPO_ADDR --topo_global_root /vitess/global"
6872
else
6973
ETCD_SERVER="localhost:2379"
7074
#TODO: Remove underscore(_) flags in v25, replace them with dashed(-) notation
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#!/bin/bash
2+
3+
# Copyright 2025 The Vitess Authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
# This is an example script that uses MySQL on 3306 as a topo server.
18+
source "$(dirname "${BASH_SOURCE[0]:-$0}")/../env.sh"
19+
20+
cell=${CELL:-'test'}
21+
22+
echo "Setting up mysql topo.."
23+
24+
# Check if MySQL is already running
25+
# Extract user, password, host and port from MYSQL_TOPO_ADDR (format: user:password@tcp(host:port)/database)
26+
MYSQL_USER_PASS=$(echo "$MYSQL_TOPO_ADDR" | sed 's/@.*//')
27+
MYSQL_USER=$(echo "$MYSQL_USER_PASS" | cut -d: -f1)
28+
MYSQL_PASS=$(echo "$MYSQL_USER_PASS" | cut -d: -f2)
29+
MYSQL_HOST_PORT=$(echo "$MYSQL_TOPO_ADDR" | sed 's/.*@tcp(\([^)]*\)).*/\1/')
30+
MYSQL_HOST=$(echo "$MYSQL_HOST_PORT" | cut -d: -f1)
31+
MYSQL_PORT=$(echo "$MYSQL_HOST_PORT" | cut -d: -f2)
32+
CREATEUSER="CREATE USER IF NOT EXISTS '${MYSQL_USER}'@'%' IDENTIFIED WITH mysql_native_password BY '${MYSQL_PASS}';"
33+
GRANTTOPO="GRANT ALL PRIVILEGES ON topo.* TO '${MYSQL_USER}'@'%'; GRANT REPLICATION SLAVE ON *.* TO '${MYSQL_USER}'@'%';"
34+
35+
# For the MySQL topo implementation we expect to have a MySQL server running.
36+
# We first try to connect as the extracted user with the extracted password.
37+
if mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -p"$MYSQL_PASS" -e "SELECT 1" > /dev/null 2>&1; then
38+
echo "MySQL is already running on $MYSQL_HOST:$MYSQL_PORT"
39+
elif mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u root -e "SELECT 1" > /dev/null 2>&1; then
40+
# if that fails, we try to connect as root with no password *and* create the topo user and then execute the GRANT statement.
41+
# if that fails, we bail and print an error message saying please create the topo user with this CREATE USER + GRANT statement.
42+
echo "MySQL is running, but '${MYSQL_USER}' does not exist. Attempting to create '${MYSQL_USER}' and grant privileges..."
43+
if ! mysql -u "$MYSQL_USER" -p"$MYSQL_PASS" -e "SELECT 1" 2>/dev/null; then
44+
if ! mysql -u root -e "$CREATEUSER" 2>/dev/null; then
45+
echo "Failed to create user '${MYSQL_USER}'@'%'."
46+
echo "Please create the user manually with the following commands:"
47+
echo " mysql -u root -e \"$CREATEUSER\""
48+
echo " mysql -u root -e \"$GRANTTOPO\""
49+
exit 1
50+
fi
51+
if ! mysql -u root -e "$GRANTTOPO" 2>/dev/null; then
52+
echo "Failed to grant privileges to '${MYSQL_USER}'@'%'."
53+
echo "Please run the following command manually:"
54+
echo " mysql -u root -e \"$GRANTTOPO\""
55+
exit 1
56+
fi
57+
fi
58+
59+
else
60+
echo "MySQL is not running, attempting to start it..."
61+
62+
# Check if we're running in Docker (by checking for /.dockerenv file)
63+
if [[ -f /.dockerenv ]]; then
64+
echo "Detected Docker environment, starting MySQL..."
65+
66+
# Create MySQL data directory and tmp directory
67+
mkdir -p "${VTDATAROOT}/mysql-topo"
68+
mkdir -p "${VTDATAROOT}/tmp"
69+
70+
# Initialize MySQL data directory if it doesn't exist
71+
if [[ ! -d "${VTDATAROOT}/mysql-topo/mysql" ]]; then
72+
echo "Initializing MySQL data directory..."
73+
mysqld --initialize-insecure --user=vitess --datadir="${VTDATAROOT}/mysql-topo" > "${VTDATAROOT}/tmp/mysql-init.out" 2>&1
74+
fi
75+
76+
# Start MySQL server
77+
echo "Starting MySQL server..."
78+
mysqld --user=vitess \
79+
--datadir="${VTDATAROOT}/mysql-topo" \
80+
--socket="${VTDATAROOT}/mysql-topo/mysql.sock" \
81+
--pid-file="${VTDATAROOT}/mysql-topo/mysql.pid" \
82+
--port="$MYSQL_PORT" \
83+
--bind-address="$MYSQL_HOST" \
84+
--skip-networking=false \
85+
--skip-mysqlx \
86+
--gtid-mode=ON \
87+
--enforce-gtid-consistency \
88+
--log-bin \
89+
--log-error="${VTDATAROOT}/tmp/mysql-topo.err" \
90+
> "${VTDATAROOT}/tmp/mysql-topo.out" 2>&1 &
91+
92+
PID=$!
93+
echo $PID > "${VTDATAROOT}/tmp/mysql-topo.pid"
94+
95+
# Wait for MySQL to start
96+
echo "Waiting for MySQL to start..."
97+
for i in {1..30}; do
98+
if mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u root -e "SELECT 1" > /dev/null 2>&1; then
99+
echo "MySQL started successfully"
100+
break
101+
fi
102+
if [[ $i -eq 30 ]]; then
103+
echo "Failed to start MySQL after 30 seconds"
104+
echo "MySQL error log:"
105+
cat "${VTDATAROOT}/tmp/mysql-topo.err" 2>/dev/null || echo "No error log found"
106+
exit 1
107+
fi
108+
sleep 1
109+
done
110+
111+
# Create the topo database
112+
echo "Creating topo database..."
113+
mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u root -e "CREATE DATABASE IF NOT EXISTS topo;" || {
114+
echo "Failed to create topo database"
115+
exit 1
116+
}
117+
# Creating the topo user and granting privileges
118+
echo "Creating topo user and granting privileges..."
119+
mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u root -e "$CREATEUSER" || {
120+
echo "Failed to create user '${MYSQL_USER}'@'%'"
121+
exit 1
122+
}
123+
mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u root -e "$GRANTTOPO" || {
124+
echo "Failed to grant privileges to '${MYSQL_USER}'@'%'"
125+
exit 1
126+
}
127+
128+
else
129+
echo "Error: MySQL is not running and this script can only auto-start MySQL in Docker environments."
130+
echo "Please start MySQL manually before calling mysql-up.sh"
131+
echo "You can start MySQL with a command like:"
132+
echo " sudo systemctl start mysql"
133+
echo " # or"
134+
echo " sudo service mysql start"
135+
echo " # or start it manually with mysqld"
136+
exit 1
137+
fi
138+
fi
139+
140+
mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -p"$MYSQL_PASS" -e "CREATE DATABASE IF NOT EXISTS topo" || true
141+
142+
# And also add the CellInfo description for the cell.
143+
# If the node already exists, it's fine, means we used existing data.
144+
echo "add ${cell} CellInfo"
145+
set +e
146+
command vtctldclient --server internal --topo-implementation mysql --topo-global-server-address $MYSQL_TOPO_ADDR AddCellInfo \
147+
--root "/vitess/${cell}" \
148+
--server-address "$MYSQL_TOPO_ADDR" \
149+
"${cell}"
150+
set -e
151+
152+
echo "mysql topo set!"

examples/local/101_initial_cluster.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ if [ "${TOPO}" = "zk2" ]; then
3333
CELL=zone1 ../common/scripts/zk-up.sh
3434
elif [ "${TOPO}" = "consul" ]; then
3535
CELL=zone1 ../common/scripts/consul-up.sh
36+
elif [ "${TOPO}" = "mysql" ]; then
37+
CELL=zone1 ../common/scripts/mysql-up.sh
3638
else
3739
CELL=zone1 ../common/scripts/etcd-up.sh
3840
fi

examples/local/501_teardown.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ if [ "${TOPO}" = "zk2" ]; then
5151
CELL=zone1 ../common/scripts/zk-down.sh
5252
elif [ "${TOPO}" = "consul" ]; then
5353
CELL=zone1 ../common/scripts/consul-down.sh
54+
elif [ "${TOPO}" = "mysql" ]; then
55+
# MySQL doesn't have a down script, since we externally manage it.
56+
# But just below in the cleanup we will empty the TOPO schema
57+
# so that it is ready for the next run.
58+
echo "The MySQL topo does not have a down script"
5459
else
5560
CELL=zone1 ../common/scripts/etcd-down.sh
5661
fi
@@ -67,6 +72,23 @@ if [ -n "$VTDATAROOT" ]; then
6772

6873
# shellcheck disable=SC2086
6974
rm -r ${VTDATAROOT:?}/*
75+
76+
# For the MySQL topo specifically, we do not store data in VTDATAROOT,
77+
# it is externally managed instead. If we don't wipe it, the next run
78+
# will fail because the MySQL topo will not be empty, and already know about
79+
# various tables causing an error:
80+
# ERROR: Cannot determine primary tablet for keyspace/shard commerce/0
81+
if [ "${TOPO}" = "mysql" ]; then
82+
echo "Cleaning up MySQL topology database..."
83+
# Extract user, password, host and port from MYSQL_TOPO_ADDR (format: user:password@tcp(host:port)/database)
84+
MYSQL_USER_PASS=$(echo "$MYSQL_TOPO_ADDR" | sed 's/@.*//')
85+
MYSQL_USER=$(echo "$MYSQL_USER_PASS" | cut -d: -f1)
86+
MYSQL_PASS=$(echo "$MYSQL_USER_PASS" | cut -d: -f2)
87+
MYSQL_HOST_PORT=$(echo "$MYSQL_TOPO_ADDR" | sed 's/.*@tcp(\([^)]*\)).*/\1/')
88+
MYSQL_HOST=$(echo "$MYSQL_HOST_PORT" | cut -d: -f1)
89+
MYSQL_PORT=$(echo "$MYSQL_HOST_PORT" | cut -d: -f2)
90+
mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -p"$MYSQL_PASS" -e "DROP DATABASE IF EXISTS topo"
91+
fi
7092
fi
7193

7294
disown -a
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
Copyright 2025 The Vitess Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package cli
18+
19+
// This plugin imports mysqltopo to register the mysql implementation of TopoServer.
20+
21+
import (
22+
_ "vitess.io/vitess/go/vt/topo/mysqltopo"
23+
)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
Copyright 2025 The Vitess Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package cli
18+
19+
// This plugin imports mysqltopo to register the mysql implementation of TopoServer.
20+
21+
import (
22+
_ "vitess.io/vitess/go/vt/topo/mysqltopo"
23+
)

go/cmd/vtctldclient/command/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import (
5353
// These imports register the topo factories to use when --server=internal.
5454
_ "vitess.io/vitess/go/vt/topo/consultopo"
5555
_ "vitess.io/vitess/go/vt/topo/etcd2topo"
56+
_ "vitess.io/vitess/go/vt/topo/mysqltopo"
5657
_ "vitess.io/vitess/go/vt/topo/zk2topo"
5758
)
5859

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
Copyright 2025 The Vitess Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package cli
18+
19+
// This plugin imports mysqltopo to register the mysql implementation of TopoServer.
20+
21+
import (
22+
_ "vitess.io/vitess/go/vt/topo/mysqltopo"
23+
)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
Copyright 2025 The Vitess Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package cli
18+
19+
// This plugin imports mysqltopo to register the mysql implementation of TopoServer.
20+
21+
import (
22+
_ "vitess.io/vitess/go/vt/topo/mysqltopo"
23+
)

0 commit comments

Comments
 (0)