本文目录导读:

我来详细介绍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("文件无法恢复");
}
}
}
注意事项
- 数据一致性:确保所有节点数据同步
- 备份策略:定期备份重要数据
- 监控告警:监控存储节点状态
- 性能测试:根据业务需求调整配置
- 安全设置:配置防火墙和访问控制
这种分布式存储方案可以提供高可用性和可扩展性,适合大规模文件存储场景。