php-fpm 运行环境下,N多并发请求到来时,如果此时缓存里没有数据,只允许一个请求去MySQL取数据然后更新缓存,其他请求再从缓存取,如何实现?
这是一个很经典的线程同步问题。你只希望有一个请求去请求MySQL,也就是希望多个线程竞争一个资源,得到资源的那一个线程才有权力访问MySQL。这是线程同步时锁起到的基本作用。撇开语言不讲,单从理论本身,常见的锁
排他锁:如数据库中的写锁。同一时间只能有一个写操作。也就是把所有操作串行化。这虽然可以达到你的目的,但是这个锁太重,对效率损伤非常严重。你已经在考虑使用缓存来加速访问,显然这样的高并发环境下排他锁不适用。
共享锁:如数据库中的读锁。多个读操作可以同时进行,但读的时候不能写。而一旦有一个写操作过来,所有读操作都必须等。
你需要的是共享锁,很多语言中会实现这类读写锁。虽然我不知道PHP有没有,对这门语言不熟,原理上讲是一样的。
先尝试获取读锁,读取缓存
发现缓存为空,提升为写锁
再次验证缓存是否为空(为什么?)
如果还是为空,则可以访问数据库读数据写缓存
释放锁
完成
这样已经把缓存刷新造成的影响降到最低,但是仍然是有额外开销的。有没有更好的办法?也是有的,不要让用户请求的线程去竞争写锁,单独运行一个线程负责定期刷新缓存,只有它去拿写锁,保证缓存里一直有东西,其他线程甚至都不用锁,只管读就好了。
线程同步即使做得再完美,对性能的损伤都是不容忽视的,所以能不做尽量不做,高并发环境里面这就是最基本的一条原则。
PS:我也不知道这个问题为什么打上MongoDB的标签。我是谁?我在哪?
5 回答3.2k 阅读✓ 已解决
3 回答3.6k 阅读✓ 已解决
1 回答4k 阅读✓ 已解决
3 回答1.8k 阅读✓ 已解决
2 回答2.2k 阅读✓ 已解决
2 回答2.8k 阅读✓ 已解决
2 回答3.1k 阅读
分布式锁 如:redis锁 set('key', 'value', ['nx', 'ex'=>10])
Gearman