锁组件
编辑该页面警告:你浏览的文档欧宝官网下载appob娱乐下载Symfony 4.4,不再维护。
读这个页面的更新版本Symfob娱乐下载ony 6.2(当前的稳定版本)。
锁组件
锁组件创建并管理锁,一个机制来提供独家访问共享资源。
如果你使用Symfony框架,阅读ob娱乐下载ob娱乐下载Symfony框架锁文件欧宝官网下载app。
安装
1
美元作曲家需要symfony /锁ob娱乐下载
请注意
如果你安装这个组件之外的Symfony应用程序,你必须要求ob娱乐下载供应商/ autoload.php
文件在你的代码,使作曲家提供的类加载机制。读这篇文章为更多的细节。
使用
锁是用来保证独占访问共享资源。例如在ob娱乐下载Symfony应用程序中,您可以使用锁来确保一个命令不执行不止一次在同一时间(在相同或不同的服务器上)。
锁是使用创建的LockFactory类,这又需要另一个类来管理存储的锁:
1 2 3 4 5
使用ob娱乐下载\组件\锁\LockFactory;使用ob娱乐下载\组件\锁\商店\SemaphoreStore;美元商店=新SemaphoreStore ();美元工厂=新LockFactory (美元商店);
4.4
的ob娱乐下载Symfony \ \锁\ LockFactory组件
类是在Symfony 4.4中引入的。ob娱乐下载在以前的版本中它被称为ob娱乐下载Symfony \锁组件\ \工厂
。
锁是通过调用创建的createLock ()方法。它的第一个参数是一个任意字符串,代表了锁定的资源。然后,调用获得()方法将尝试获得锁:
1 2 3 4 5 6 7 8 9
/ /……美元锁=美元工厂- >createLock (“pdf-invoice-generation”);如果(美元锁- >获得()){/ /资源“pdf-invoice-generation”是锁着的。/ /这里可以安全地计算并生成发票。美元锁- >release ();}
如果不能获得锁,方法返回假
。的获得()
方法可以安全地调用多次,即使已经获得锁。
请注意
与其他实现,即使锁组件区分锁实例创建相同的资源。这意味着对于一个给定的范围和资源实例可以多次获得一个锁。如果锁必须使用多个服务,他们应该共享相同的锁
返回的实例LockFactory: createLock
方法。
提示
如果你不显式地释放锁,它将自动释放实例销毁。在某些情况下,它可以帮助锁定资源跨多个请求。禁用自动释放行为,第三个参数的设置createLock ()
方法假
。
序列化锁
的关键包含的状态锁并且可以序列化。这允许用户开始长工作过程中通过收购锁,并继续工作在另一个进程使用相同的锁:
1 2 3 4 5 6 7 8
使用ob娱乐下载\组件\锁\关键;使用ob娱乐下载\组件\锁\锁;美元关键=新键(“文章”。。美元文章- >getId ());美元锁=新锁(美元关键,美元这- >商店,300年,假);美元锁- >获得(真正的);美元这- >公共汽车- >调度(新RefreshTaxonomy (美元文章,美元关键));
请注意
别忘了禁用autoRelease避免析构函数被调用时释放锁。
并不是所有的商店都兼容序列化和跨进程锁定:例如,内核将自动释放信号量收购SemaphoreStore商店。如果你使用一个不兼容的商店,会抛出一个异常,当应用程序想要序列化的关键。
阻塞锁
默认情况下,当无法获得一个锁,收购
方法返回假
立即。等到(无限期)锁可以创建,通过真正的
的论点获得()
方法。这被称为阻塞锁因为您的应用程序的执行停止,直到锁。
一些内置的商店
类支持这一特性。当他们不,他们可以装饰着RetryTillSaveStore
类:
1 2 3 4 5 6 7 8 9 10
使用ob娱乐下载\组件\锁\LockFactory;使用ob娱乐下载\组件\锁\商店\RedisStore;使用ob娱乐下载\组件\锁\商店\RetryTillSaveStore;美元商店=新RedisStore (新\ Predis \客户端(“tcp: / / localhost: 6379”));美元商店=新RetryTillSaveStore (美元商店);美元工厂=新LockFactory (美元商店);美元锁=美元工厂- >createLock (“notification-flush”);美元锁- >获得(真正的);
到期的锁
锁创建远程很难管理,因为没有远程方式商店
知道柜过程仍然活着。由于错误,致命错误或分割的缺点,它不能保证release ()
方法将调用,这将导致资源无限。
在这种情况下是创建最好的解决方案到期的锁一段时间后,自动释放已通过(TTL呼吁生存时间)。这一次,在几秒钟内,第二个参数的配置createLock ()
方法。如果需要,还可以释放这些锁的早期release ()
方法。
使用锁定到期时最棘手的部分是选择合适的TTL。如果太短了,其他进程可以获得锁之前完成工作;如果太长和过程调用之前崩溃release ()
方法,资源将保持锁定,直到超时:
1 2 3 4 5 6 7 8 9 10 11 12
/ /……/ /创建一个锁定到期,持续30秒(默认值是300.0)美元锁=美元工厂- >createLock (“charts-generation”,30.);如果(!美元锁- >获得()){返回;}试一试{/ /执行工作期间少于30秒}最后{美元锁- >release ();}
提示
避免锁处于锁定状态,建议将工作在一个try / catch / finally块中总是试图到期释放锁。
在长时间运行的任务的情况下,最好开始不久TTL,然后使用refresh ()方法重置TTL到原来的值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/ /……美元锁=美元工厂- >createLock (“charts-generation”,30.);如果(!美元锁- >获得()){返回;}试一试{而(!美元完成了){/ /执行工作的一小部分。/ /更新锁30秒钟。美元锁- >refresh ();}}最后{美元锁- >release ();}
提示
另一个有用的技术,长时间运行的任务是通过一个自定义的TTL作为参数refresh ()
方法来改变默认的锁TTL:
1 2 3 4 5 6 7
美元锁=美元工厂- >createLock (“charts-generation”,30.);/ /……/ /刷新锁,持续30秒美元锁- >refresh ();/ /……/ /刷新锁定为600秒(下刷新()调用将再次30秒)美元锁- >刷新(600年);
该组件还提供了两个相关的有用的方法锁:到期getRemainingLifetime ()
(返回零
或者一个浮动
秒)和isExpired ()
(返回一个布尔值)。
自动释放锁
锁锁对象被破坏时自动释放。这是一个实现细节,将重要的进程间共享锁时。在下面的示例中,pcntl_fork ()
创建两个过程和锁会自动释放一个过程完成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/ /……美元锁=美元工厂- >createLock (报告生成的,3600年);如果(!美元锁- >获得()){返回;}美元pid= pcntl_fork ();如果(1= = =美元pid){/ /不能叉退出(1);}elseif(美元pid){/ /父进程睡眠(30.);}其他的{/ /子进程回声“现在锁将被释放。”;退出(0);}/ /……
设置为禁用此行为假
第三个参数的LockFactory: createLock ()
。这将让3600秒或直到锁了锁::释放()
被称为。
锁的所有者
首次获得锁是[1]_的拥有锁
实例,获得它。如果你需要检查当前是否锁
实例(仍然)锁的主人,您可以使用isAcquired ()
方法:
1 2 3
如果(美元锁- >isAcquired ()) {/ /我们(仍然)自己的锁}
因为有些锁商店到期锁(如上看到并解释了),有可能失去锁自动获得一个实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/ /如果我们不能获得自己,这意味着一些其他流程已经工作如果(!美元锁- >获得()){返回;}美元这- >beginTransaction ();/ /执行一个非常漫长的过程,可能超过TTL的锁如果(美元锁- >isAcquired ()) {/ /还好,没有其他实例获得锁的同时,我们的安全美元这- >commit ();}其他的{/ /懒汉!我们的锁已经明显超过了TTL和另一个进程已经开始/ /同时对我们来说是不安全的承诺。美元这- >rollback ();扔新\异常(“过程失败”);}
谨慎
一个常见的陷阱可能会使用isAcquired ()
方法检查是否锁已经获得的任何过程。正如你所看到的在这个例子中,你必须使用获得()
对于这个。的isAcquired ()
方法用于检查是否锁被收购当前进程只有!
-
. .[1]从技术上讲,真正的主人锁的共享相同的实例
关键
, -
不
锁
。但从用户的角度来看,关键
是内部的,你可能只会使用吗锁
所以很容易认为的实例锁
实例是一个锁的所有者。
可用的商店
锁是创建和管理商店
类,实现PersistingStoreInterface可选地,BlockingStoreInterface。
内置存储组件包括以下类型:
商店 | 范围 | 阻塞 | 即将到期的 |
---|---|---|---|
FlockStore | 当地的 | 是的 | 没有 |
MemcachedStore | 远程 | 没有 | 是的 |
PdoStore | 远程 | 没有 | 是的 |
RedisStore | 远程 | 没有 | 是的 |
SemaphoreStore | 当地的 | 是的 | 没有 |
ZookeeperStore | 远程 | 没有 | 没有 |
4.4
的PersistingStoreInterface
和BlockingStoreInterface
接口是在Symfony 4.4中引入的。ob娱乐下载在以前的版本中只有一个接口调用ob娱乐下载Symfony \ \锁\ StoreInterface组件
。
FlockStore
FlockStore使用本地计算机上的文件系统创建锁。它不支持过期,但锁时自动释放锁对象超出范围,由垃圾收集器释放(例如PHP过程结束时):
1 2 3 4 5
使用ob娱乐下载\组件\锁\商店\FlockStore;/ /参数是锁的目录的路径/ /如果没有,sys_get_temp_dir()内部使用。美元商店=新FlockStore (/ var /商店的);
谨慎
注意,一些文件系统(比如某些类型的NFS)不支持锁定。在这些情况下,最好使用本地磁盘驱动器上的一个目录或一个远程存储基于PDO,复述或Memcached。
MemcachedStore
MemcachedStore保存锁在Memcached服务器上,它需要一个Memcached连接实现\ Memcached
类。这家商店不支持阻塞,并预计TTL避免停滞锁:
1 2 3 4 5 6
使用ob娱乐下载\组件\锁\商店\MemcachedStore;美元memcached=新\ Memcached ();美元memcached- >addServer (“localhost”,11211年);美元商店=新MemcachedStore (美元memcached);
请注意
Memcached不支持TTL低于1秒。
PdoStore
PdoStore保存锁在一个SQL数据库。它需要一个PDO连接,教义DBAL连接,或者一个数据源名称(DSN)。这家商店不支持阻塞,并预计TTL避免停滞锁:
1 2 3 4 5
使用ob娱乐下载\组件\锁\商店\PdoStore;/ /一个PDO,教义DBAL连接通过PDO懒惰或DSN连接美元databaseConnectionOrDSN=“mysql:主机= 127.0.0.1;dbname =锁';美元商店=新PdoStore (美元databaseConnectionOrDSN,(“db_username”= >“myuser”,“db_password”= >“我的密码”]);
请注意
这家商店不支持TTL低于1秒。
在数据库中存储锁之前,您必须创建表,存储信息。商店提供了一个方法调用不知道()为你设置此表根据所使用的数据库引擎:
1 2 3 4 5
试一试{美元商店- >不知道();}抓(\ PDOException美元异常){/ /创建的表不能因为某些原因}
设置表在生产的好办法是调用不知道()
方法在您的本地计算机,然后生成一个数据库迁移:
1 2
美元php bin /控制台学说:迁移:diff美元php bin /控制台学说:迁移:迁移
RedisStore
RedisStore保存复述,服务器上的锁,它需要复述,连接实现\复述,
,\ RedisArray
,\ RedisCluster
或\ Predis
类。这家商店不支持阻塞,并预计TTL避免停滞锁:
1 2 3 4 5 6
使用ob娱乐下载\组件\锁\商店\RedisStore;美元复述,=新\复述();美元复述,- >连接(“localhost”);美元商店=新RedisStore (美元复述,);
SemaphoreStore
SemaphoreStore使用PHP信号量函数创建锁:
1 2 3
使用ob娱乐下载\组件\锁\商店\SemaphoreStore;美元商店=新SemaphoreStore ();
CombinedStore
CombinedStore是专为高可用性的应用程序,因为它管理几个店铺同步(例如,几个复述,服务器)。锁被收购时,它将调用转发给所有的存储管理,并收集他们的反应。如果一个简单多数的商店获得锁,然后被认为是获得锁;否则就不会获得:
1 2 3 4 5 6 7 8 9 10 11 12 13
使用ob娱乐下载\组件\锁\商店\CombinedStore;使用ob娱乐下载\组件\锁\商店\RedisStore;使用ob娱乐下载\组件\锁\策略\ConsensusStrategy;美元商店= [];foreach([“server1”,server2的,“server3”]作为美元服务器){美元复述,=新\复述();美元复述,- >连接(美元服务器);美元商店[]=新RedisStore (美元复述,);}美元商店=新CombinedStore (美元商店,新ConsensusStrategy ());
而不是简单多数的策略(ConsensusStrategy
)一个UnanimousStrategy
可用于需要获得锁所有的商店。
谨慎
为了得到高可用性时使用ConsensusStrategy
,最低必须三个服务器集群大小。这允许集群继续工作当一个服务器失败(因为这个策略需要锁在超过一半的服务器)。
ZookeeperStore
ZookeeperStore保存锁上动物园管理员服务器。它需要一个动物园管理员连接实现\动物园管理员
类。这家商店不支持阻塞和过期但锁是PHP时自动释放过程终止:
1 2 3 4 5 6 7
使用ob娱乐下载\组件\锁\商店\ZookeeperStore;美元动物园管理员=新\管理员(“localhost: 2181”);/ /定义一个高可用性集群使用以下:/ /管理员美元= new \管理员(“localhost1:2181, localhost2:2181, localhost3:2181”);美元商店=新ZookeeperStore (美元动物园管理员);
请注意
动物园管理员不需要TTL节点用于锁定是短暂的和死当PHP进程终止。
可靠性
组件保证相同的资源不能被锁定两次只要组件中使用以下方式。
远程存储
远程商店(MemcachedStore,PdoStore,RedisStore和ZookeeperStore)使用一个独特的标记识别真正的所有者的锁。这令牌存储在关键对象和内部使用的锁
。
每个并发进程必须存储锁
在相同的服务器上。否则两个不同的机器上可能让两个不同的进程获得相同的锁
。
谨慎
保证相同的服务器总是安全的,不使用Memcached loadbalance后面,一个集群或循环DNS。即使主服务器,调用不能转发到一个备份或故障转移服务器。
到期的商店
到期的商店(MemcachedStore,PdoStore和RedisStore)保证了锁只对定义的持续时间。如果任务花费的时间完成,然后锁可以存储和发布的被别人收购。
的锁
提供了几个方法来检查它的健康。的isExpired ()
方法检查是否结束,其一生getRemainingLifetime ()
方法返回的时间住在秒。
使用上面的方法,一个更健壮的代码是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/ /……美元锁=美元工厂- >createLock (“invoice-publication”,30.);如果(!美元锁- >获得()){返回;}而(!美元完成了){如果(美元锁- >getRemainingLifetime () < =5){如果(美元锁- >isExpired ()) {/ /锁丢了,执行回滚或发送一个通知扔新\ RuntimeException (锁在整体过程中丢失的);}美元锁- >refresh ();}/ /执行任务的时间必须小于5分钟}
谨慎
做出明智的选择的生命周期锁
并检查其是否剩余时间就足以完成任务的生活。
谨慎
存储锁
通常需要几毫秒,但网络环境可能会增加时间(几秒钟)。选择正确的TTL时考虑。
通过设计,锁都存储在服务器上定义的生命周期。如果机器的日期或时间变化,锁被释放的时间可能早于预期。
谨慎
保证日期不会改变,国家结核控制规划服务应该禁用和日期应该在服务停止时更新。
FlockStore
通过使用文件系统,这一点商店
是可靠的,只要并发进程使用相同的物理目录来存储锁。
过程必须运行在同一台机器上,虚拟机或容器。更新Kubernetes或群服务时要小心,因为很短的时间内,可以有两个容器并行运行。
目录的绝对路径必须是相同的。小心随时可以改变的符号链接:Capistrano和蓝色/绿色部署经常使用这个技巧。该目录路径改变时要小心两个部署。
一些文件系统(比如某些类型的NFS)不支持锁定。
谨慎
所有的并发进程必须使用相同的物理文件系统通过运行在同一台机器上,使用相同的绝对路径锁定目录。
根据定义,使用的FlockStore
在一个HTTP上下文与多个前端服务器不兼容,除非以确保相同的资源总是被锁定在同一台机器上或者使用一个共享文件系统配置。
文件系统上的文件可以删除在维护操作。例如,清理/ tmp
目录或重新启动机器后,一个目录使用tmpfs。这不是一个问题,如果释放锁过程结束后,但在锁
请求之间重用。
谨慎
不锁存储在文件系统不稳定,如果他们必须在多个请求中重用。
MemcachedStore
Memcached的工作方式是将物品存储在内存中。这意味着,通过使用MemcachedStore锁不坚持,随时可能消失的错误。
如果Memcached服务或者重启机器托管,每个锁将丢失没有通知正在运行的流程。
谨慎
为了避免别人获得一个锁在重启之后,建议推迟服务开始和等待至少只要TTL最长的锁。
默认Memcached使用LRU机制删除旧条目当服务需要空间来添加新项目。
谨慎
物品的数量必须控制存储在Memcached。如果这是不可能的,应该禁用LRU和锁应存放在一个专门的Memcached远离缓存服务。
当Memcached服务共享和用于多个使用,锁可能是被错误。例如一些PSR-6的实现clear ()
方法使用Memcached冲洗()
方法清洗并删除一切。
谨慎
该方法冲洗()
不能,或锁应存放在一个专门的Memcached远离缓存服务。
PdoStore
PdoStore依赖酸属性的SQL引擎。
谨慎
在一个集群中配置了多个初选,确保写同步传播到每个节点,或者总是使用相同的节点。
谨慎
MySQL允许禁用等一些SQL引擎独特的约束检查。确保事实并非如此设置unique_checks = 1;
。
为了清除旧的锁,这个商店使用当前日期时间来定义一个过期日期参考。这种机制依赖于所有服务器节点的时钟同步。
谨慎
确保锁不要过早失效;ttl应设置有足够的额外的时间占任何节点间时钟漂移。
RedisStore
复述的工作方式是将物品存储在内存中。这意味着,通过使用RedisStore锁不坚持,随时可能消失的错误。
如果复述,服务或者重启机器托管,每个锁将丢失没有通知正在运行的流程。
谨慎
为了避免别人获得一个锁在重启之后,建议推迟服务开始和等待至少只要TTL最长的锁。
提示
复述,可以配置为存在磁盘上的项目,但这个选项会慢下来写在服务。这可能与其他用途的服务器。
当复述,服务共享和用于多种用途,锁可能是被错误。
谨慎
命令FLUSHDB
不能,或锁应存放在一个专门的复述,远离缓存服务。
CombinedStore
结合商店允许锁跨多个后端存储。这是一个常见的错误认为锁机制将更加可靠。这是错误的。的CombinedStore
会,在最好的情况下,可靠的所有管理商店是最可靠的。一旦一个托管存储返回的错误信息,CombinedStore
不会是可靠的。
谨慎
所有的并发进程必须使用相同的配置,与相同数量的存储和管理相同的端点。
提示
而不是使用一个复述或Memcached服务器集群,这是更好的使用CombinedStore
与单个服务器/存储管理。
SemaphoreStore
信号量是由内核级别。为了是可靠的,过程必须运行在同一台机器上,虚拟机或容器。更新Kubernetes或群体服务的时候要小心,因为很短的时间内,可以有两个并行运行的容器。
谨慎
所有的并发进程必须使用相同的机器。在开始新机器上的并发进程之前,检查其他进程在旧的停止。
谨慎
当运行在systemd和非系统的用户选择RemoveIPC = yes
(默认值),锁systemd当用户删除的日志。检查过程运行系统用户(UID < = SYS_UID_MAX)SYS_UID_MAX
中定义的/etc/login.defs
或设置选项RemoveIPC =了
在/etc/systemd/logind.conf
。
ZookeeperStore
ZookeeperStore的工作方式是通过保持锁短暂的节点服务器上。这意味着,通过使用ZookeeperStore锁会自动释放会话结束时,以防客户端无法打开任何理由。
如果管理员服务或者重启机器托管,每个锁将丢失没有通知正在运行的流程。
提示
使用管理员的高可用性特性,您可以设置多个服务器集群,这样在其中一个服务器宕机情况下,大多数仍将服务请求。所有可用的服务器集群中会看到相同的状态。
请注意
这家商店不支持多级节点锁,因为中间节点成为一个开销的清理,所有的锁都是保持在根级别。
整体
更改配置的商店应该非常仔细地做。例如,在一个新版本的部署。流程与新配置时不得启动旧流程与旧的配置仍然运行。