PHP项目本地分布式存储如何搭建使用

wen PHP项目 26

本文目录导读:

PHP项目本地分布式存储如何搭建使用

  1. 常见解决方案
  2. MinIO 搭建方案(推荐)
  3. PHP 集成代码
  4. 使用示例
  5. 配置优化
  6. 性能优化建议
  7. 故障恢复
  8. 注意事项

我来详细介绍PHP项目本地分布式存储的搭建和使用方案。

常见解决方案

1 文件系统方案

  • NFS (Network File System)
  • GlusterFS
  • MooseFS

2 对象存储方案

  • MinIO (最推荐)
  • SeaweedFS
  • FastDFS

MinIO 搭建方案(推荐)

1 单机多节点部署

# 下载MinIO
wget https://dl.min.io/server/minio/release/linux-amd64/minio
chmod +x minio
# 启动多个实例(模拟分布式)
# 节点1
minio server /data/node1 --console-address :9001
# 节点2  
minio server /data/node2 --console-address :9002
# 节点3
minio server /data/node3 --console-address :9003

2 Docker部署

# docker-compose.yml
version: '3.7'
services:
  minio1:
    image: minio/minio:latest
    hostname: minio1
    volumes:
      - ./data1:/data
    ports:
      - "9001:9001"
      - "9000:9000"
    environment:
      MINIO_ROOT_USER: admin
      MINIO_ROOT_PASSWORD: admin123
    command: server /data --console-address ":9001"
  minio2:
    image: minio/minio:latest
    hostname: minio2
    volumes:
      - ./data2:/data
    ports:
      - "9002:9002"
      - "9003:9003"
    environment:
      MINIO_ROOT_USER: admin
      MINIO_ROOT_PASSWORD: admin123
    command: server /data --console-address ":9002"

PHP 集成代码

1 安装依赖

composer require aws/aws-sdk-php
# 或
composer require minio/minio-php

2 MinIO PHP客户端

<?php
// MinIO 配置类
class MinioConfig {
    private static $instance = null;
    private $client;
    private function __construct() {
        $this->client = new Minio\MinioClient(
            'http://localhost:9000', // 任意节点地址
            'admin',                 // Access Key
            'admin123'              // Secret Key
        );
    }
    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    public function getClient() {
        return $this->client;
    }
}
// 文件上传类
class FileStorage {
    private $client;
    private $bucket;
    public function __construct($bucket = 'uploads') {
        $this->client = MinioConfig::getInstance()->getClient();
        $this->bucket = $bucket;
        $this->initBucket();
    }
    private function initBucket() {
        if (!$this->client->bucketExists($this->bucket)) {
            $this->client->makeBucket($this->bucket);
            // 设置公开读权限
            $policy = json_encode([
                'Version' => '2012-10-17',
                'Statement' => [
                    [
                        'Effect' => 'Allow',
                        'Principal' => ['AWS' => ['*']],
                        'Action' => ['s3:GetObject'],
                        'Resource' => ["arn:aws:s3:::{$this->bucket}/*"]
                    ]
                ]
            ]);
            $this->client->setBucketPolicy($this->bucket, $policy);
        }
    }
    public function upload($localPath, $remotePath = null) {
        try {
            $remotePath = $remotePath ?: basename($localPath);
            $result = $this->client->putObject(
                $this->bucket,
                $remotePath,
                fopen($localPath, 'rb'),
                null
            );
            return [
                'success' => true,
                'path' => $remotePath,
                'url' => $this->getUrl($remotePath)
            ];
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
    public function uploadFromContent($content, $remotePath) {
        try {
            $result = $this->client->putObject(
                $this->bucket,
                $remotePath,
                $content,
                null
            );
            return [
                'success' => true,
                'path' => $remotePath,
                'url' => $this->getUrl($remotePath)
            ];
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
    public function getUrl($path) {
        return "http://localhost:9000/{$this->bucket}/{$path}";
    }
    public function delete($path) {
        try {
            $this->client->removeObject($this->bucket, $path);
            return ['success' => true];
        } catch (Exception $e) {
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }
    public function listFiles($prefix = '') {
        $objects = $this->client->listObjects($this->bucket, $prefix);
        $files = [];
        foreach ($objects as $obj) {
            $files[] = [
                'name' => $obj->getKey(),
                'size' => $obj->getSize(),
                'modified' => $obj->getLastModified()
            ];
        }
        return $files;
    }
}

3 AWS S3协议兼容(推荐)

<?php
// 使用 AWS SDK (兼容 MinIO)
require 'vendor/autoload.php';
use Aws\S3\S3Client;
use Aws\Exception\AwsException;
class DistributedStorage {
    private $s3;
    private $bucket;
    public function __construct() {
        $this->s3 = new S3Client([
            'version' => 'latest',
            'region'  => 'us-east-1',
            'endpoint' => 'http://localhost:9000', // MinIO地址
            'use_path_style_endpoint' => true,
            'credentials' => [
                'key'    => 'admin',
                'secret' => 'admin123',
            ],
        ]);
        $this->bucket = 'myapp';
        $this->initBucket();
    }
    private function initBucket() {
        if (!$this->s3->doesBucketExist($this->bucket)) {
            $this->s3->createBucket(['Bucket' => $this->bucket]);
        }
    }
    public function uploadFile($source, $destination) {
        try {
            $result = $this->s3->putObject([
                'Bucket' => $this->bucket,
                'Key'    => $destination,
                'SourceFile' => $source,
                'ACL'    => 'public-read'
            ]);
            return [
                'success' => true,
                'url' => $result['ObjectURL'],
                'etag' => $result['ETag']
            ];
        } catch (AwsException $e) {
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
    public function uploadFromStream($stream, $destination) {
        try {
            $result = $this->s3->putObject([
                'Bucket' => $this->bucket,
                'Key'    => $destination,
                'Body'   => $stream,
                'ACL'    => 'public-read'
            ]);
            return ['success' => true, 'url' => $result['ObjectURL']];
        } catch (Exception $e) {
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }
    public function getPresignedUrl($path, $expires = '+1 hour') {
        $command = $this->s3->getCommand('GetObject', [
            'Bucket' => $this->bucket,
            'Key'    => $path
        ]);
        $request = $this->s3->createPresignedRequest($command, $expires);
        return (string) $request->getUri();
    }
    public function deleteFile($path) {
        try {
            $this->s3->deleteObject([
                'Bucket' => $this->bucket,
                'Key'    => $path
            ]);
            return ['success' => true];
        } catch (Exception $e) {
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }
}

使用示例

<?php
// 上传文件
$storage = new DistributedStorage();
// 上传本地文件
$result = $storage->uploadFile('/path/to/local/file.jpg', 'images/2024/01/file.jpg');
echo $result['url']; // 返回访问URL
// 上传二进制数据
$imageData = file_get_contents('https://example.com/image.jpg');
$result = $storage->uploadFromStream($imageData, 'images/remote.jpg');
// 生成临时访问链接
$url = $storage->getPresignedUrl('images/2024/01/file.jpg', '+1 day');
// 删除文件
$result = $storage->deleteFile('images/old.jpg');

配置优化

1 Nginx反向代理

upstream minio_servers {
    server 127.0.0.1:9000;
    server 127.0.0.1:9003;
    server 127.0.0.1:9006;
}
server {
    listen 80;
    server_name storage.example.com;
    location / {
        proxy_pass http://minio_servers;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        # 大文件上传
        client_max_body_size 100M;
        client_body_buffer_size 128k;
        proxy_connect_timeout 300;
        proxy_send_timeout 300;
        proxy_read_timeout 300;
    }
}

2 配置PHP

; php.ini
upload_max_filesize = 100M
post_max_size = 100M
max_execution_time = 300
memory_limit = 256M

性能优化建议

1 本地缓存

<?php
class CacheStorage extends DistributedStorage {
    private $cacheDir = '/tmp/file-cache';
    private $cacheTime = 3600; // 缓存1小时
    public function __construct() {
        parent::__construct();
        if (!is_dir($this->cacheDir)) {
            mkdir($this->cacheDir, 0755, true);
        }
    }
    public function getFile($path) {
        $cachePath = $this->cacheDir . '/' . md5($path);
        // 检查缓存
        if (file_exists($cachePath) && (time() - filemtime($cachePath)) < $this->cacheTime) {
            return file_get_contents($cachePath);
        }
        // 从分布式存储获取
        $result = $this->s3->getObject([
            'Bucket' => $this->bucket,
            'Key' => $path
        ]);
        $content = $result['Body']->getContents();
        file_put_contents($cachePath, $content);
        return $content;
    }
}

2 异步上传

<?php
// 使用队列异步处理上传
class AsyncUploader {
    private $queue;
    public function __construct() {
        // 使用Redis或其他队列
        $this->queue = new RedisQueue();
    }
    public function queueUpload($localPath, $remotePath = null) {
        $remotePath = $remotePath ?: basename($localPath);
        $this->queue->push([
            'action' => 'upload',
            'local_path' => $localPath,
            'remote_path' => $remotePath,
            'timestamp' => time()
        ]);
        return ['queued' => true, 'path' => $remotePath];
    }
    public function processQueue() {
        while ($job = $this->queue->pop()) {
            $storage = new DistributedStorage();
            $storage->uploadFile($job['local_path'], $job['remote_path']);
        }
    }
}

故障恢复

<?php
class ReliableStorage {
    private $backups = [];
    public function uploadWithBackup($source, $destination, $backupCount = 2) {
        $result = [];
        // 上传到主存储
        $storage = new DistributedStorage();
        $result['primary'] = $storage->uploadFile($source, $destination);
        // 创建备份
        for ($i = 1; $i <= $backupCount; $i++) {
            $backupPath = $destination . ".backup{$i}";
            $this->backups[] = [
                'path' => $backupPath,
                'timestamp' => time()
            ];
            $result['backup_' . $i] = $storage->uploadFile($source, $backupPath);
        }
        return $result;
    }
    public function getWithFallback($path) {
        $storage = new DistributedStorage();
        try {
            return $storage->getFile($path);
        } catch (Exception $e) {
            // 尝试从备份恢复
            foreach ($this->backups as $backup) {
                if (strpos($backup['path'], $path) === 0) {
                    try {
                        return $storage->getFile($backup['path']);
                    } catch (Exception $e) {
                        continue;
                    }
                }
            }
            throw new Exception("文件无法恢复");
        }
    }
}

注意事项

  1. 数据一致性:确保所有节点数据同步
  2. 备份策略:定期备份重要数据
  3. 监控告警:监控存储节点状态
  4. 性能测试:根据业务需求调整配置
  5. 安全设置:配置防火墙和访问控制

这种分布式存储方案可以提供高可用性和可扩展性,适合大规模文件存储场景。

抱歉,评论功能暂时关闭!