API Platform数据库复制:主从架构配置

API Platform数据库复制:主从架构配置

【免费下载链接】api-platform api-platform/api-platform: API Platform是一个基于Symfony和PHP构建的现代化API开发框架,旨在简化创建高性能、易于维护的REST和GraphQL APIs的过程。它支持Hydra(JSON-LD)和Swagger规范,内置了对数据过滤、排序、分页等功能的支持,并可轻松与 Doctrine ORM 或 MongoDB 集成。 【免费下载链接】api-platform 项目地址: https://gitcode.com/gh_mirrors/ap/api-platform

你还在为API高并发下的数据库性能问题发愁吗?还在担心单点故障导致服务不可用吗?本文将带你一步步实现API Platform的数据库主从复制架构,解决数据读写分离和高可用性难题。读完本文,你将掌握:主从数据库环境搭建、Symfony配置多数据源、读写分离中间件集成、数据同步监控的完整解决方案。

为什么需要主从架构

数据库是大多数API应用的性能瓶颈,尤其当你的API平台面临以下挑战时:

  • 读多写少场景下的性能瓶颈
  • 数据备份与灾难恢复需求
  • 数据分析与业务系统分离
  • 高可用性与负载均衡要求

API Platform作为基于Symfony和PHP的现代化API框架,通过Doctrine ORM提供了灵活的数据库访问层,使得实现主从复制架构变得简单可控。

架构概览

主从复制架构的核心是将数据库读写操作分离:

mermaid

环境准备

数据库环境

本教程使用MySQL作为示例数据库,需要准备:

  • 1台主数据库服务器
  • 至少1台从数据库服务器
  • 所有数据库服务器版本保持一致

项目文件结构

API Platform的数据库配置主要通过以下文件管理:

主数据库配置

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

测试读写分离

  1. 通过API创建一条记录(写操作,主库)
  2. 立即查询该记录(读操作,从库)
  3. 验证数据是否同步

性能优化建议

  1. 增加从库数量:根据读请求量横向扩展从库
  2. 延迟容忍策略:非关键读操作允许一定数据延迟
  3. 查询缓存:结合api/config/packages/cache.yaml配置结果缓存
  4. 连接池优化:调整数据库连接池大小
# api/config/packages/doctrine.yaml
doctrine:
    dbal:
        connections:
            default:
                # ...
                pool:
                    max_connections: 20
            slave:
                # ...
                pool:
                    max_connections: 50

总结与展望

通过本文的步骤,你已经成功实现了API Platform的数据库主从复制架构。这一架构不仅提高了系统的可用性和扩展性,还为后续的微服务拆分和多区域部署奠定了基础。

下一步,你可以考虑:

  • 实现从库的负载均衡
  • 自动故障转移机制
  • 数据分片与分区策略
  • 结合Mercure协议实现数据实时同步

希望本文对你构建高性能API平台有所帮助!如果你有任何问题或建议,请在评论区留言。别忘了点赞收藏,关注获取更多API Platform实战教程!

【免费下载链接】api-platform api-platform/api-platform: API Platform是一个基于Symfony和PHP构建的现代化API开发框架,旨在简化创建高性能、易于维护的REST和GraphQL APIs的过程。它支持Hydra(JSON-LD)和Swagger规范,内置了对数据过滤、排序、分页等功能的支持,并可轻松与 Doctrine ORM 或 MongoDB 集成。 【免费下载链接】api-platform 项目地址: https://gitcode.com/gh_mirrors/ap/api-platform

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值