Symfony Lock 锁机制详解
基本概念
Symfony Lock组件提供了一种协调多个进程或服务器之间资源访问的机制,用于避免并发操作导致的数据冲突。

安装
composer require symfony/lock
配置和存储类型
1 支持的存储后端
# config/packages/framework.yaml
framework:
lock:
# 使用文件系统存储
file_system_lock:
resource: '%kernel.cache_dir%/locks'
type: 'flock'
# 使用Redis
redis_lock:
resource: 'redis://localhost'
type: 'redis'
# 使用Memcached
memcached_lock:
resource: 'memcached://localhost'
type: 'memcached'
# 使用数据库
pdo_lock:
resource: 'mysql:host=localhost;dbname=mydb'
type: 'pdo'
username: 'root'
password: ''
基本用法
1 简单锁示例
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Lock\Store\FlockStore;
// 创建锁存储
$store = new FlockStore('/path/to/locks');
$factory = new LockFactory($store);
// 创建锁
$lock = $factory->createLock('resource-name');
// 尝试获取锁
if ($lock->acquire()) {
// 执行需要同步的代码
try {
// 处理敏感操作
processPayment();
} finally {
// 释放锁
$lock->release();
}
}
2 使用阻塞方式
use Symfony\Component\Lock\Store\RedisStore;
use Symfony\Component\Lock\LockFactory;
$redis = new Redis();
$redis->connect('127.0.0.1');
$store = new RedisStore($redis);
$factory = new LockFactory($store);
// 创建锁,设置超时时间
$lock = $factory->createLock('payment-lock', 30); // 30秒超时
// 阻塞等待锁(默认无限等待)
$lock->acquire(true); // 阻塞等待
// 或者指定最大等待时间
$lock->acquire(true, 10); // 最多等待10秒
// 也可以检查是否获取到锁
if ($lock->acquire(true, 5)) {
try {
// 处理任务
updatePoints();
} finally {
$lock->release();
}
}
高级特性
1 自动过期
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Lock\Store\RedisStore;
$store = new RedisStore($redis);
$factory = new LockFactory($store);
// 锁会自动过期,防止死锁
$lock = $factory->createLock('cronjob-lock', 60); // 60秒后自动释放
if ($lock->acquire()) {
try {
// 长时间运行的任务
processHeavyTask();
// 刷新锁的过期时间(延长锁定时间)
$lock->refresh();
continueProcessing();
} finally {
$lock->release();
}
}
2 信号量锁
use Symfony\Component\Lock\Store\SemaphoreStore;
// 使用信号量(仅支持Linux)
$store = new SemaphoreStore();
$factory = new LockFactory($store);
$lock = $factory->createLock('semaphore-lock');
实际应用场景
1 防止重复提交
class OrderController
{
private LockFactory $lockFactory;
public function createOrder(Request $request)
{
$userId = $this->getUser()->getId();
$lock = $this->lockFactory->createLock("order-creation-{$userId}", 10);
if (!$lock->acquire()) {
throw new \Exception('请勿重复提交');
}
try {
// 处理订单创建
$order = $this->createOrder();
// 更新库存
$this->updateStock($order);
return $this->json($order);
} finally {
$lock->release();
}
}
}
2 定时任务控制
class CronJobService
{
public function runCashJob()
{
$lock = $this->lockFactory->createLock('cron-cash-job', 300);
if (!$lock->acquire()) {
$this->logger->info('将金任务正在运行中,跳过');
return;
}
try {
// 执行将金计算
$this->processCashUpdate();
} finally {
$lock->release();
}
}
}
3 分布式锁示例
use Symfony\Component\Lock\Store\RedisStore;
use Symfony\Component\Lock\LockFactory;
// Redis存储是最常用的分布式锁实现
class DistributedLockService
{
private LockFactory $lockFactory;
public function __construct()
{
$redis = new \Redis();
$redis->connect('redis-master', 6379);
$store = new RedisStore($redis);
$this->lockFactory = new LockFactory($store);
}
public function processWithLock(string $resourceId): bool
{
$lock = $this->lockFactory->createLock(
"resource:{$resourceId}",
30, // TTL
true // 自动刷新
);
if (!$lock->acquire()) {
return false;
}
try {
// 执行分布式任务
$this->executeCriticalTask($resourceId);
return true;
} finally {
$lock->release();
}
}
}
最佳实践
1 始终使用 try-finally
$lock = $factory->createLock('resource');
$lock->acquire();
try {
// 业务逻辑
} finally {
$lock->release();
}
2 合理的超时设置
// 根据业务时间设置合适的TTL
$lock = $factory->createLock('resource', 10); // 10秒
// 避免设置过长或过短
// 太短:任务可能没完成就释放
// 太长:影响其他进程
3 监控锁状态
if ($lock->acquire()) {
// 检查锁是否仍被当前进程持有
if ($lock->isAcquired()) {
// 安全执行代码
}
}
4 连接池配置(Redis)
# config/packages/framework.yaml
framework:
lock:
redis:
resource: 'redis://localhost'
options:
# 连接池配置
persistent: true
timeout: 5
retry_interval: 100
常见问题及解决方案
1 死锁预防
// 设置合理的TTL防止死锁
$lock = $factory->createLock('resource', 30);
// 使用refresh()方法维持锁
$lock->acquire();
$lock->refresh(); // 刷新过期时间
2 锁竞争优化
// 使用更细粒度的锁
// 不好的做法
$lock = $factory->createLock('all-users', 30);
// 好的做法
$lock = $factory->createLock("user-{$userId}", 30);
// 使用读写锁来处理不同场景
3 锁释放失败处理
try {
$lock->acquire();
// 业务代码
} catch (\Exception $e) {
// 确保释放锁
if ($lock->isAcquired()) {
$lock->release();
}
throw $e;
}
Symfony Lock组件提供了一套完整的锁机制实现,支持多种存储后端,适用于单机和分布式环境,合理使用锁机制可以有效避免并发问题,但需要注意死锁预防、性能影响和适当的事务设计,在选择锁存储时,Redis是最推荐的分布式锁实现,而文件锁适合单机应用。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播