{"id":44457973,"url":"https://github.com/laincloud/mysql-service","last_synced_at":"2026-02-12T18:08:41.370Z","repository":{"id":57603509,"uuid":"58015122","full_name":"laincloud/mysql-service","owner":"laincloud","description":"A layer 2 service providing MySQL storage for LAIN's applications","archived":false,"fork":false,"pushed_at":"2018-08-31T12:09:53.000Z","size":4275,"stargazers_count":3,"open_issues_count":0,"forks_count":2,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-06-20T11:18:08.037Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/laincloud.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-05-04T02:00:11.000Z","updated_at":"2023-03-08T09:09:03.000Z","dependencies_parsed_at":"2022-09-26T19:52:48.299Z","dependency_job_id":null,"html_url":"https://github.com/laincloud/mysql-service","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/laincloud/mysql-service","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laincloud%2Fmysql-service","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laincloud%2Fmysql-service/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laincloud%2Fmysql-service/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laincloud%2Fmysql-service/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/laincloud","download_url":"https://codeload.github.com/laincloud/mysql-service/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laincloud%2Fmysql-service/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29375740,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-12T08:51:36.827Z","status":"ssl_error","status_checked_at":"2026-02-12T08:51:26.849Z","response_time":55,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2026-02-12T18:08:40.594Z","updated_at":"2026-02-12T18:08:41.364Z","avatar_url":"https://github.com/laincloud.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MySQL service\n[![Build Status](https://travis-ci.org/laincloud/mysql-service.svg?branch=master)](https://travis-ci.org/laincloud/mysql-service) [![MIT license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://opensource.org/licenses/MIT)\n\n![首页](https://github.com/laincloud/mysql-service/blob/master/etc/photo/overview.png)\n\n\n![监控](https://github.com/laincloud/mysql-service/blob/master/etc/photo/details.png)\n\n\n\n## 1. Introduction\nMySQL Service是LAIN中能够提供稳定MySQL存储的layer2服务型应用。对于依赖mysql作为数据库的应用，MySQL Service是这些应用的首选。相对于直接部署在物理节点的MySQL，MySQL Service的主要功能有：\n- 智能代理：MySQL service的portal是一个传输层的智能代理，能够根据实例的主从状态将MySQL的连接请求代理到正确的实例。\n- 支持单主、单备、多从的多实例集群结构：由于MySQL Service是集群中的可选组件，因此在部署时可以选择多实例，并在运维的Web UI中将实例进行角色注册。\n- 完善的主从、主备切换：在MySQL运维过程中，主从或主备切换是必不可少的工作。MySQL Service提供了较为完善的切换功能，能够最大限度地减少对客户端的影响。\n- 人性化的Web UI：基于bootstrap构建的GUI，为数据库管理员(DBA)提供了一键注册实例、一键切主、一键建立数据同步的功能，使得DBA可以避免去编写繁杂的运维脚本，降低运维失误。\n- 运行状态监控：在集群配置了监控系统（如Graphite）的情况下，可以将实例的运行状态实时上报至监控系统。\n- 数据自动备份：在集群配置了**backupd**的情况下，可以通过backupd实现基于[percona-xtrabackup-2.2.12](https://www.percona.com/doc/percona-xtrabackup/2.2/release-notes/2.2/2.2.12.html)的全量物理备份以及增量的binlog备份。这两者都是数据恢复的基础。\n- 密码安全保障：MySQL Service的root，repl，dba密码需要在应用部署前通过**secret file**机制注入到container内部的文件，避免了密码以明文的形式出现在代码库中。\n- 身份验证：如果集群开启了sso验证机制，所有在Web上的运维操作都必须经过sso身份验证。且只有属于MySQL Service的用户组的用户（即DBA）才能通过身份验证。\n\nMySQL Service适用的场景：\n- 依赖MySQL数据库应用的测试。\n- 流量、数据量适中的数据库应用运行。\n- 不需要独占实例的数据库应用。\n\nMySQL Service不适用的场景：\n- 需要多主和HA。\n- 需要独占实例（请使用MySQL Resource）。\n- 数据库访问量巨大，对性能要求极高的。\n- 有特殊运维需求的。\n\nMySQL Service依赖的LAIN组件：\n- lainlet（必需）\n- backupd（可选，自动备份依赖）\n- sso（可选，身份验证依赖）\n- lvault（可选，数据库初始化时root/repl/dba密码配置依赖）\n\n## 2. Architecture\n\n### 2.1 Architecture Overview\n\n![Resize icon](etc/photo/mysql-service-init_structure.png)\n\n### 2.2 Monitor\n\n#### 2.2.1 Cluster Initialization\nmysql_monitor经过编译会生成monitord程序。monitord从lainlet中监听mysql-server的instance数量变化信息，同时从本地存储的配置文件中得到集群状态（第一次部署时文件中没有集群状态）。当集群状态改变时，monitor会将改变后的状态刷新到配置文件中。\n\n#### 2.2.2 Server Sent Event for Proxy\nmonitord会启动Server Sent Event（SSE）服务。服务地址为`http://\u003cmonitor_host\u003e:6033/servers`。当有新的MySQLProxy连接时，会发送init事件。当监听的lainlet推送update事件时，会发送update事件。\n   SSE的推送的信息data字段的信息为json串，内容如下：\n\n```json\n{\"master\":\n    {\"containers\":\n        [{\"container_ip\" : \"xxx\",\n          \"container_port\" : xxx\n        }]\n    },\n \"slave\":\n    {\"containers\":\n        [{\"container_ip\" : \"xxx\",\n          \"container_port\" : xxx\n         },\n         {\"container_ip\" : \"xxx\",\n          \"container_port\" : xxx\n         }]\n    }\n}\n```\n\n#### 2.2.3 Web UI Monitor\n\nmonitor基于Go的[beego](http://beego.me) web框架实现，提供了web可视化监控功能。部署后可以从`http://mysql-service.LAIN_DOMAIN` 进入首页。但是前提要登录过SSO并具有**mysql-service**的**write:group**权限。如果没有登录，web控制台会自动跳转回console的登录页面。\n\nOverview页面展示了各个节点的工作状态，并且提供了主从、主备切换以及在master故障时的紧急切换（主备优先，如果没有standby则进行主从切换）。切换时的规则如下：\n\n- 正常情况下的主备/从切换（Switch with standby/slave）: 如果切换前是单向主备，则切换后也为单向主备；如果切换前是互相主备，切换后也为互相主备。当standby/某个slave的状态为OK时，可以主动切换。\n且切换成功只是保证实现了master和standby/slave的角色互换，不保证所有的slave均切换成功，因此还需要观察slave的运行状态是否为`OK`。\n- 异常情况下的主备/从切换（Emergency Switch）: **只有master状态为`ERROR`时，才能进行该操作** 。并且优先执行主备切换，如果没有standby则任找一台slave做主从切换。该操作不保证切换后的master一定可用，并且不保证master－standby的关系不发生变化，同时也不保证所有的slave成功完成切换master。\n因此当master挂掉时，建议结合Unregister操作以及进入容器调查等方式决定新的的master（例如将standby unregister并且将工作正常的slave unregister然后register为standby，这样Emergency Switch时就会进行主备切换）和决定是否执行Emergency Switch。\n\nOverview页面还提供了注册、反注册；激活、分离；暂停、恢复等操作链接，每对操作均为互逆操作。其中规则如下：\n\n- 节点一开始均处于`UNREGISTERED`状态，注册(Register)操作可以讲该节点注册到管理列表中，但其行为并未发生改变（即不会建立任何主从关系）。集群中可以注册最多一个master，一个standby，但是可以有多个slave。master注册后如果工作状态正常则状态值为`OK`，standby和slave则为`DETACHED`。\n- 注册后的节点可以反注册（Unregister），从而可以从管理列表中删除。但是同样地，该操作不影响节点的行为。\n- 注册后的standby和slave可以通过激活（Active）操作建立与master的主从关系，如果工作正常则状态为`OK`，如果与主节点同步连接正常但是数据不同步，则状态为`SYNING`。如果配置了standby，对master执行激活操作可以建立master到standby的反向主从，用于实现master和standby的互备。\n- 激活的standby和slave可以通过分离（Detach）操作解除与master的主从关系，解除后其状态变为`DETACHED`。\n- 任何运行正常的节点均可以通过暂停（Pause）操作暂停该节点的对外服务（主节点会设为只读，其他节点则会暂停slave），且状态均会变为`PAUSE`。\n- 处于`PAUSE`状态的节点可以通过恢复（Resume）操作恢复该节点的对外服务。\n- 如果standby和slave的Maste_Host和master不一致（多出现在该节点宕机时发生了主从或主备切换的情况），该节点的状态为`LOST`，此时通过Active操作即可恢复正常。\n- 如果某个节点无法连接，则状态值为`ERROR`。\n\n点击Details并在下拉菜单中选择某个节点则进入对应节点的详细信息页面，该页面展示了该节点的角色，而且如果该节点配置了master，则展示出该节点的SLAVE_STATUS。同时还有性能信息。表格中可以通过查找方式找到特定的项。\n\n#### 2.2.4 Stats Data Reporting\n\nmonitor在启动时会定期向监控系统推送所有实例的状态数据。\n\n状态信息的获得目前包括：\n - `SHOW SLAVE STATUS`\n - `SHOW GLOBAL STATUS`\n - `SHOW GLOBAL VARIABLES`\n - `SHOW ENGINE InnoDB STATUS`\n\n### 2.3 Proxy\n\n#### 2.3.1 Auto Updating Target Endpoints\n\n   mysql_proxy经过编译会生成proxyd程序。proxyd程序运行时需指定两个参数:\n\n- `-p`: 监听客户端请求的端口号。既然是MySQLProxy，则建议设置为**3306**。\n- `-m`: 转发模式。取值为slave或master，分别代表将数据转发到slave实例或master实例。\n\n\u003e 如果有多个slave实例，连接请求会随机代理到某一个实例上。\n\nproxyd启动时连接monitor的SSE服务。当monitor推送事件时，proxyd会根据data更新目的地址列表，该过程是线程安全的。\n\n\u003e 由于proxyd是传输层代理，因此在切换目的地址时不会主动断掉旧的连接（防止直接断掉TCP连接后，MySQL无法收到`RESET`请求出现连接泄露）。中断连接的过程在MySQL服务端执行。\n\n#### 2.3.2 Proxy Requests Between Clients and Servers\n\n   proxyd会在启动时在`-p`设置的端口上监听来自客户端的TCP连接请求。\n\n   当proxyd接收到客户端的连接请求后，会再建立一个goroutine处理该请求。新建立的goroutine会从目的地址列表中按照轮询的规则找到一个目的地址，在查找的过程会加上读锁。当确定地址后，会建立两个goroutine传输数据，分别传输client-\u003etarget和target-\u003eclient直至传输结束。\n\n## 3. License\nMySQL-Service遵循[MIT](https://github.com/laincloud/mysql-service/blob/master/LICENSE)开源协议。\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flaincloud%2Fmysql-service","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flaincloud%2Fmysql-service","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flaincloud%2Fmysql-service/lists"}