API Platform数据库复制:主从架构配置
你还在为API高并发下的数据库性能问题发愁吗?还在担心单点故障导致服务不可用吗?本文将带你一步步实现API Platform的数据库主从复制架构,解决数据读写分离和高可用性难题。读完本文,你将掌握:主从数据库环境搭建、Symfony配置多数据源、读写分离中间件集成、数据同步监控的完整解决方案。
为什么需要主从架构
数据库是大多数API应用的性能瓶颈,尤其当你的API平台面临以下挑战时:
- 读多写少场景下的性能瓶颈
- 数据备份与灾难恢复需求
- 数据分析与业务系统分离
- 高可用性与负载均衡要求
API Platform作为基于Symfony和PHP的现代化API框架,通过Doctrine ORM提供了灵活的数据库访问层,使得实现主从复制架构变得简单可控。
架构概览
主从复制架构的核心是将数据库读写操作分离:
环境准备
数据库环境
本教程使用MySQL作为示例数据库,需要准备:
- 1台主数据库服务器
- 至少1台从数据库服务器
- 所有数据库服务器版本保持一致
项目文件结构
API Platform的数据库配置主要通过以下文件管理:
- api/config/packages/doctrine.yaml - Doctrine ORM核心配置
- api/.env - 环境变量配置
- api/src/Repository/ - 自定义仓库类存放目录
主数据库配置
MySQL主库设置
修改MySQL配置文件my.cnf:
[mysqld]
server-id=1
log_bin=mysql-bin
binlog_do_db=api_platform_db
binlog_ignore_db=mysql
binlog_ignore_db=information_schema
expire_logs_days=7
max_binlog_size=100M
binlog_format=ROW
重启MySQL服务并创建复制用户:
CREATE USER 'repl_user'@'%' IDENTIFIED BY 'your_secure_password';
GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'%';
FLUSH PRIVILEGES;
主库状态检查
获取主库状态信息,记录File和Position值:
SHOW MASTER STATUS;
从数据库配置
MySQL从库设置
修改从库配置文件my.cnf:
[mysqld]
server-id=2
relay_log=mysql-relay-bin
log_slave_updates=1
read_only=1
replicate_do_db=api_platform_db
配置主从连接
在从库执行以下命令,替换为你的主库信息:
CHANGE MASTER TO
MASTER_HOST='master_db_host',
MASTER_USER='repl_user',
MASTER_PASSWORD='your_secure_password',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=154;
START SLAVE;
检查从库状态
验证主从同步状态:
SHOW SLAVE STATUS\G
确保以下两个参数值为Yes:
- Slave_IO_Running: Yes
- Slave_SQL_Running: Yes
Symfony多数据源配置
修改Doctrine配置
编辑api/config/packages/doctrine.yaml文件,配置主从连接:
doctrine:
dbal:
default_connection: default
connections:
default:
url: '%env(resolve:DATABASE_URL_MASTER)%'
driver: 'pdo_mysql'
server_version: '8.0'
charset: utf8mb4
slave:
url: '%env(resolve:DATABASE_URL_SLAVE)%'
driver: 'pdo_mysql'
server_version: '8.0'
charset: utf8mb4
orm:
default_entity_manager: default
entity_managers:
default:
connection: default
mappings:
App:
is_bundle: false
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App
slave:
connection: slave
mappings:
App:
is_bundle: false
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App
配置环境变量
编辑api/.env文件,添加数据库连接信息:
DATABASE_URL_MASTER="mysql://db_user:db_password@master_db:3306/api_platform_db?serverVersion=8.0&charset=utf8mb4"
DATABASE_URL_SLAVE="mysql://db_user:db_password@slave_db:3306/api_platform_db?serverVersion=8.0&charset=utf8mb4"
实现读写分离
创建自定义仓库基类
在api/src/Repository/目录下创建ReadOnlyRepository.php:
<?php
namespace App\Repository;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
abstract class ReadOnlyRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry, string $entityClass)
{
parent::__construct($registry, $entityClass);
$this->_em = $this->getEntityManager('slave');
}
}
实体仓库实现
为需要读取的实体创建仓库类,继承自定义的只读仓库:
<?php
namespace App\Repository;
use App\Entity\Greeting;
use Doctrine\Persistence\ManagerRegistry;
class GreetingRepository extends ReadOnlyRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Greeting::class);
}
// 自定义查询方法
public function findRecentGreetings(int $limit = 10): array
{
return $this->createQueryBuilder('g')
->orderBy('g.createdAt', 'DESC')
->setMaxResults($limit)
->getQuery()
->getResult();
}
}
写操作使用主库
对于写操作,确保使用默认的实体管理器:
<?php
namespace App\Controller;
use App\Entity\Greeting;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
class GreetingController extends AbstractController
{
public function createGreeting(Request $request, EntityManagerInterface $em): JsonResponse
{
$data = json_decode($request->getContent(), true);
$greeting = new Greeting();
$greeting->setMessage($data['message']);
$greeting->setCreatedAt(new \DateTime());
// 默认使用主库连接
$em->persist($greeting);
$em->flush();
return $this->json($greeting, 201);
}
}
数据同步监控
添加健康检查端点
创建数据库健康检查控制器,监控主从同步状态:
<?php
namespace App\Controller;
use Doctrine\DBAL\Connection;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
class DatabaseHealthController extends AbstractController
{
public function checkSlaveStatus(Connection $connection): JsonResponse
{
$status = $connection->executeQuery('SHOW SLAVE STATUS')->fetchAssociative();
$isHealthy = $status['Slave_IO_Running'] === 'Yes' && $status['Slave_SQL_Running'] === 'Yes';
return $this->json([
'status' => $isHealthy ? 'ok' : 'error',
'slave_io_running' => $status['Slave_IO_Running'],
'slave_sql_running' => $status['Slave_SQL_Running'],
'seconds_behind_master' => $status['Seconds_Behind_Master']
]);
}
}
配置监控路由
编辑api/config/routes.yaml添加健康检查路由:
database_health_check:
path: /_health/database
controller: App\Controller\DatabaseHealthController::checkSlaveStatus
methods: GET
部署与测试
Docker Compose配置
编辑compose.yaml添加主从数据库服务:
version: '3.8'
services:
db-master:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root_password
MYSQL_DATABASE: api_platform_db
MYSQL_USER: db_user
MYSQL_PASSWORD: db_password
volumes:
- ./mysql-master:/var/lib/mysql
- ./mysql-master-config:/etc/mysql/conf.d
ports:
- "3306:3306"
db-slave:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root_password
MYSQL_DATABASE: api_platform_db
MYSQL_USER: db_user
MYSQL_PASSWORD: db_password
volumes:
- ./mysql-slave:/var/lib/mysql
- ./mysql-slave-config:/etc/mysql/conf.d
ports:
- "3307:3306"
depends_on:
- db-master
启动服务
使用Docker Compose启动整个环境:
docker-compose up -d
测试读写分离
- 通过API创建一条记录(写操作,主库)
- 立即查询该记录(读操作,从库)
- 验证数据是否同步
性能优化建议
- 增加从库数量:根据读请求量横向扩展从库
- 延迟容忍策略:非关键读操作允许一定数据延迟
- 查询缓存:结合api/config/packages/cache.yaml配置结果缓存
- 连接池优化:调整数据库连接池大小
# api/config/packages/doctrine.yaml
doctrine:
dbal:
connections:
default:
# ...
pool:
max_connections: 20
slave:
# ...
pool:
max_connections: 50
总结与展望
通过本文的步骤,你已经成功实现了API Platform的数据库主从复制架构。这一架构不仅提高了系统的可用性和扩展性,还为后续的微服务拆分和多区域部署奠定了基础。
下一步,你可以考虑:
- 实现从库的负载均衡
- 自动故障转移机制
- 数据分片与分区策略
- 结合Mercure协议实现数据实时同步
希望本文对你构建高性能API平台有所帮助!如果你有任何问题或建议,请在评论区留言。别忘了点赞收藏,关注获取更多API Platform实战教程!
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



