{"id":18048037,"url":"https://github.com/ivangfr/springboot-proxysql-mysql","last_synced_at":"2025-04-10T09:48:07.210Z","repository":{"id":50659803,"uuid":"189657450","full_name":"ivangfr/springboot-proxysql-mysql","owner":"ivangfr","description":"The goal of this project is to use ProxySQL to load balance requests from a Spring-Boot application to MySQL Replication Master-Slave Cluster.","archived":false,"fork":false,"pushed_at":"2024-12-18T16:47:14.000Z","size":1386,"stargazers_count":13,"open_issues_count":1,"forks_count":15,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-24T08:42:28.257Z","etag":null,"topics":["java","mysql","proxysql","spring-boot","spring-data-jpa","spring-web-mvc"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ivangfr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"ivangfr"}},"created_at":"2019-05-31T20:56:22.000Z","updated_at":"2025-02-17T22:06:15.000Z","dependencies_parsed_at":"2024-10-30T20:21:09.266Z","dependency_job_id":null,"html_url":"https://github.com/ivangfr/springboot-proxysql-mysql","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivangfr%2Fspringboot-proxysql-mysql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivangfr%2Fspringboot-proxysql-mysql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivangfr%2Fspringboot-proxysql-mysql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivangfr%2Fspringboot-proxysql-mysql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ivangfr","download_url":"https://codeload.github.com/ivangfr/springboot-proxysql-mysql/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248197128,"owners_count":21063587,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","mysql","proxysql","spring-boot","spring-data-jpa","spring-web-mvc"],"created_at":"2024-10-30T20:11:04.207Z","updated_at":"2025-04-10T09:48:07.191Z","avatar_url":"https://github.com/ivangfr.png","language":"Java","funding_links":["https://github.com/sponsors/ivangfr"],"categories":[],"sub_categories":[],"readme":"# springboot-proxysql-mysql\n\nThe goal of this project is to use [`ProxySQL`](https://proxysql.com/) to load balance requests from a [`Spring Boot`](https://docs.spring.io/spring-boot/index.html) application to [`MySQL`](https://www.mysql.com/) Replication Master-Slave Cluster.\n\n## Proof-of-Concepts \u0026 Articles\n\nOn [ivangfr.github.io](https://ivangfr.github.io), I have compiled my Proof-of-Concepts (PoCs) and articles. You can easily search for the technology you are interested in by using the filter. Who knows, perhaps I have already implemented a PoC or written an article about what you are looking for.\n\n## Additional Readings\n\n- \\[**Medium**\\] [**Optimizing Spring Boot’s Connection to MySQL Master-Slave Clusters with ProxySQL**](https://medium.com/@ivangfr/optimizing-spring-boots-connection-to-mysql-master-slave-clusters-with-proxysql-af275a0a4cea)\n\n## Project Architecture\n\n![project-diagram](documentation/project-diagram.jpeg)\n\n## Applications\n\n- ### MySQL\n\n  [`MySQL`](https://www.mysql.com/) is the most popular Open Source SQL database management system, supported by `Oracle`. In this project, we set a **MySQL Replication Master-Slave Cluster** that contains three `MySQL` instances: one master and two slaves. In the replication process, the data is copied automatically from master to the slaves.\n\n- ### ProxySQL\n\n  [`ProxySQL`](https://proxysql.com/) is an open-source, high-performance `MySQL` proxy server. It seats between application and database servers by accepting incoming traffic from `MySQL` clients and forwards it to backend `MySQL` servers. In this project, we set two `hostgroups`: `writer=10` and `reader=20`. Those hostgroups say to which database servers write or read requests should go. The `MySQL` master belongs to the `writer` hostgroup. On the other hand, the slaves belong to `reader` one.\n\n- ### customer-api\n\n  `Spring Boot` Web Java application that exposes a REST API for managing customers. Instead of connecting directly to `MySQL`, as usual, the application will be connected to `ProxySQL`.\n\n  `customer-api` has the following endpoints:\n  ```\n     GET /api/customers\n     GET /api/customers/{id}\n    POST /api/customers {\"firstName\":\"...\", \"lastName\":\"...\"}\n     PUT /api/customers/{id} {\"firstName\":\"...\", \"lastName\":\"...\"}\n  DELETE /api/customers/{id}\n  ```\n\n## Prerequisites\n\n- [`Java 21+`](https://www.oracle.com/java/technologies/downloads/#java21)\n- Some containerization tool [`Docker`](https://www.docker.com), [`Podman`](https://podman.io), etc.\n\n## Start Environment\n\n- Open a terminal and, inside the `springboot-proxysql-mysql` root folder, run the following script:\n  ```\n  ./init-environment.sh\n  ```\n\n- Wait until the environment is up and running\n\n## Check MySQL Replication\n\n- In a terminal, make sure you are inside the `springboot-proxysql-mysql` root folder;\n\n- To check the replication status run:\n  ```\n  ./check-replication-status.sh\n  ```\n\n  You should see something like:\n  ```\n  mysql-master\n  ------------\n  File  Position  Binlog_Do_DB  Binlog_Ignore_DB  Executed_Gtid_Set\n  mysql-bin-1.000003  1397      62a2f52f-b16b-11ed-91fc-0242c0a85002:1-14\n  \n  mysql-slave-1\n  -------------\n  *************************** 1. row ***************************\n                 Slave_IO_State: Waiting for master to send event\n                    Master_Host: mysql-master\n                    Master_User: replication\n                    Master_Port: 3306\n                  Connect_Retry: 60\n                Master_Log_File: mysql-bin-1.000003\n            Read_Master_Log_Pos: 1397\n                 Relay_Log_File: fa249eba35d6-relay-bin.000003\n                  Relay_Log_Pos: 1614\n          Relay_Master_Log_File: mysql-bin-1.000003\n               Slave_IO_Running: Yes\n              Slave_SQL_Running: Yes\n                                 ...\n  \n  mysql-slave-2\n  -------------\n  *************************** 1. row ***************************\n                 Slave_IO_State: Waiting for master to send event\n                    Master_Host: mysql-master\n                    Master_User: replication\n                    Master_Port: 3306\n                  Connect_Retry: 60\n                Master_Log_File: mysql-bin-1.000003\n            Read_Master_Log_Pos: 1397\n                 Relay_Log_File: cbfd1f4bb01a-relay-bin.000003\n                  Relay_Log_Pos: 1614\n          Relay_Master_Log_File: mysql-bin-1.000003\n               Slave_IO_Running: Yes\n              Slave_SQL_Running: Yes\n                                 ...\n  ```\n\n## Check ProxySQL configuration\n\n- In a terminal and inside the `springboot-proxysql-mysql` root folder, run the script below to connect to `ProxySQL` command line terminal:\n  ```\n  ./proxysql-admin.sh\n  ```\n\n- In `ProxySQL Admin\u003e ` terminal run the following command to see the `MySQL` servers: \n  ```\n  SELECT * FROM mysql_servers;\n  ```\n\n- The following select shows the global variables:\n  ```\n  SELECT * FROM global_variables;\n  ```\n  \n- In order to exit `ProxySQL` command line terminal, type `exit`.\n\n## Start customer-api\n\n- In a terminal and navigate to the `springboot-proxysql-mysql` root folder;\n\n- Run the following Maven command to start the application:\n  ```\n  ./mvnw clean spring-boot:run --projects customer-api\n  ```\n\n## Simulation\n\n1. Open three terminals: one for `mysql-master`, one for `mysql-slave-1` and another for `mysql-slave-2`;\n\n2. In `mysql-master` terminal, connect to `MySQL Monitor` by running:\n   ```\n   docker exec -it -e MYSQL_PWD=secret mysql-master mysql -uroot --database customerdb\n   ```\n\n3. Do the same for `mysql-slave-1`...\n   ```\n   docker exec -it -e MYSQL_PWD=secret mysql-slave-1 mysql -uroot --database customerdb\n   ```\n\n4. ... and `mysql-slave-2`\n   ```\n   docker exec -it -e MYSQL_PWD=secret mysql-slave-2 mysql -uroot --database customerdb\n   ```\n\n5. Inside each `MySQL Monitor's` terminal, run the following commands to enable `MySQL` logs:\n   ```\n   SET GLOBAL general_log = 'ON';\n   SET global log_output = 'table';\n   ```\n\n6. Open a new terminal. In it, we will just run `curl` commands;\n\n7. In the `curl` terminal, let's create a customer:\n   ```\n   curl -i -X POST http://localhost:8080/api/customers \\\n     -H 'Content-Type: application/json' \\\n     -d '{\"firstName\": \"Ivan\", \"lastName\": \"Franchin\"}'\n   ```\n   \n8. Go to `mysql-master` terminal and run the following `SELECT` command:\n   ```\n   SELECT event_time, command_type, SUBSTRING(argument,1,250) argument FROM mysql.general_log\n   WHERE command_type = 'Query' AND (argument LIKE 'insert into customers %' OR argument LIKE 'select c1_0.id%' OR argument LIKE 'update customers %' OR argument LIKE 'delete from customers %');\n   ```\n\n   It should return:\n   ```\n   +----------------------------+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------+\n   | event_time                 | command_type | argument                                                                                                                                        |\n   +----------------------------+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------+\n   | 2023-02-20 22:13:15.400178 | Query        | insert into customers (created_at, first_name, last_name, updated_at) values ('2023-02-20 22:13:15', 'Ivan', 'Franchin', '2023-02-20 22:13:15') |\n   +----------------------------+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------+\n   ```\n   \n   \u003e **Note**: If you run the same `SELECT` in the slave's terminal, you will see that just the `mysql-master` processed the `insert` command. Btw, it's in `mysql-master` where all inserts, updates and deletes are executed.\n\n9. Now, let's call to the `GET` endpoint to retrieve `customer 1`. For it, go to `curl` terminal and run:\n   ```\n   curl -i http://localhost:8080/api/customers/1\n   ```\n\n10. If you run, in one of the slave's terminal, the `SELECT` command below:\n    ```\n    SELECT event_time, command_type, SUBSTRING(argument,1,250) argument FROM mysql.general_log\n    WHERE command_type = 'Query' AND (argument LIKE 'insert into customers %' OR argument LIKE 'select c1_0.id%' OR argument LIKE 'update customers %' OR argument LIKE 'delete from customers %');\n    ```\n\n    It should return:\n    ```\n    +----------------------------+--------------+-------------------------------------------------------------------------------------------------------------------+\n    | event_time                 | command_type | argument                                                                                                          |\n    +----------------------------+--------------+-------------------------------------------------------------------------------------------------------------------+\n    | 2023-02-20 22:14:06.582449 | Query        | select c1_0.id,c1_0.created_at,c1_0.first_name,c1_0.last_name,c1_0.updated_at from customers c1_0 where c1_0.id=1 |\n    +----------------------------+--------------+-------------------------------------------------------------------------------------------------------------------+\n    ```\n    \u003e **Note**: Just one slave should process it.\n\n11. Next, let's `UPDATE` the `customer 1`. For it, go to the `curl` terminal and run:\n    ```\n    curl -i -X PUT http://localhost:8080/api/customers/1 \\\n      -H 'Content-Type: application/json' \\\n      -d '{\"firstName\": \"Ivan2\", \"lastName\": \"Franchin2\"}'\n    ```\n\n12. Running the following `SELECT` inside the `mysql-master` terminal:\n    ```\n    SELECT event_time, command_type, SUBSTRING(argument,1,250) argument FROM mysql.general_log\n    WHERE command_type = 'Query' AND (argument LIKE 'insert into customers %' OR argument LIKE 'select c1_0.id%' OR argument LIKE 'update customers %' OR argument LIKE 'delete from customers %');\n    ```\n\n    It should return:\n    ```\n    +----------------------------+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------+\n    | event_time                 | command_type | argument                                                                                                                                        |\n    +----------------------------+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------+\n    | 2023-02-20 22:13:15.400178 | Query        | insert into customers (created_at, first_name, last_name, updated_at) values ('2023-02-20 22:13:15', 'Ivan', 'Franchin', '2023-02-20 22:13:15') |\n    | 2023-02-20 22:14:33.019875 | Query        | update customers set created_at='2023-02-20 22:13:15', first_name='Ivan2', last_name='Franchin2', updated_at='2023-02-20 22:14:33' where id=1   |\n    +----------------------------+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------+\n    ```\n    \u003e **Note**: During an update, Hibernate/JPA does a select before performing the record update. So, you should see another select in one of the slaves \n\n13. Finally, let's `DELETE` the `customer 1`. For it, go to the `curl` terminal and run:\n    ```\n    curl -i -X DELETE http://localhost:8080/api/customers/1\n    ```\n\n14. Running the following `SELECT` inside the `mysql-master` terminal:\n    ```\n    SELECT event_time, command_type, SUBSTRING(argument,1,250) argument FROM mysql.general_log\n    WHERE command_type = 'Query' AND (argument LIKE 'insert into customers %' OR argument LIKE 'select c1_0.id%' OR argument LIKE 'update customers %' OR argument LIKE 'delete from customers %');\n    ```\n\n    It should return:\n    ```\n    +----------------------------+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------+\n    | event_time                 | command_type | argument                                                                                                                                        |\n    +----------------------------+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------+\n    | 2023-02-20 22:13:15.400178 | Query        | insert into customers (created_at, first_name, last_name, updated_at) values ('2023-02-20 22:13:15', 'Ivan', 'Franchin', '2023-02-20 22:13:15') |\n    | 2023-02-20 22:14:33.019875 | Query        | update customers set created_at='2023-02-20 22:13:15', first_name='Ivan2', last_name='Franchin2', updated_at='2023-02-20 22:14:33' where id=1   |\n    | 2023-02-20 22:14:52.358207 | Query        | delete from customers where id=1                                                                                                                |\n    +----------------------------+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------+\n    ```\n    \u003e **Note**: As it happens with an update, during a deletion, Hibernate/JPA does a select before performing the deletion of the record. So, you should see another select in one of the slaves\n\n## Shutdown\n\n- To stop `customer-api` application, go to the terminal where it's running and press `Ctrl+C`;\n- In order to get out of `MySQL Monitors` type `exit`;\n- To stop and remove `MySQL`s and `ProxySQL` containers, network and volumes, make sure you are inside the `springboot-proxysql-mysql` root folder and run the following script:\n  ```\n  ./shutdown-environment.sh\n  ```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivangfr%2Fspringboot-proxysql-mysql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fivangfr%2Fspringboot-proxysql-mysql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivangfr%2Fspringboot-proxysql-mysql/lists"}