Dalam sistem teragih, memandangkan berbilang nod beroperasi pada sumber yang sama pada masa yang sama, konflik konkurensi terdedah kepada berlaku. Untuk menyelesaikan masalah ini, kami biasanya menggunakan kunci yang diedarkan untuk mengawal akses kepada sumber yang dikongsi. Redis ialah cache teragih yang cekap yang boleh digunakan untuk melaksanakan kunci teragih. Artikel ini akan memperkenalkan cara menggunakan Redis dalam PHP untuk melaksanakan kunci teragih dan merealisasikan penukaran pintar.
1. Apakah kunci teragih?
Kunci teragih bermakna apabila berbilang nod mengakses sumber kongsi, hanya satu nod boleh mengendalikan sumber tersebut dan nod lain perlu menunggu. Kunci yang diedarkan mengandungi dua operasi: memperoleh kunci dan melepaskan kunci. Operasi mendapatkan kunci perlu memastikan keselamatan benang dan mengelakkan pemerolehan kunci berulang kali perlu memastikan kunci dilepaskan dengan betul untuk mengelakkan kebuntuan.
2. Gunakan Redis untuk melaksanakan kunci teragih
Redis ialah pangkalan data dalam memori yang boleh mengakses data dengan cepat dan menyokong pengedaran. Dalam Redis, anda boleh menggunakan perintah set untuk menetapkan kunci dan nilai Jika kunci tidak wujud, tetapan boleh berjaya jika kunci sudah wujud, tetapan akan gagal. Ciri ini boleh digunakan untuk melaksanakan kunci teragih.
Pelaksanaan khusus boleh dibahagikan kepada dua langkah. Langkah pertama ialah memperoleh kunci Gunakan perintah set untuk menetapkan kunci Jika tetapan berjaya, ini bermakna kunci telah berjaya diperolehi. Langkah kedua ialah melepaskan kunci dan gunakan perintah del untuk memadamkan kunci.
Berikut ialah contoh kod PHP yang menggunakan Redis untuk melaksanakan kunci teragih:
class RedisLock{ protected $redis; protected $lockKey = 'distributed_lock'; protected $timeout = 30; // 默认锁超时时间30s function __construct(){ $this->redis = new Redis(); $this->redis->connect('127.0.0.1', 6379); } function getRedisClient(){ return $this->redis; } function setLock($key = ''){ if(empty($key)){ $key = $this->lockKey; }else{ $key = $this->lockKey . '_' . $key; // 如果有传入锁键名,则拼接上前缀方便管理 } $timeout = $this->timeout; while ($timeout > 0) { // 如果锁未超时,则等待获取锁 $result = $this->redis->set($key, time() + $timeout, ['nx', 'ex' => $timeout]); if ($result){ return true; } sleep(1); // 每次等待1秒钟 $timeout = $timeout -1; } return false; } function unlock($key = ''){ if(empty($key)){ $key = $this->lockKey; }else{ $key = $this->lockKey . '_' . $key; // 如果有传入锁键名,则拼接上前缀方便管理 } return $this->redis->del($key); } }
Gunakan kelas ini untuk mendapatkan kunci dengan mudah:
$lock = new RedisLock(); if($lock->setLock()){ // 执行需要获得锁的操作 $lock->unlock(); }
3
Pelaksanaan kunci yang diedarkan di atas agak mudah, tetapi apabila kegagalan nod berlaku, ia akan menyebabkan masalah. Sebagai contoh, pemasaan: Nod A memperoleh kunci, tetapi menemui kerosakan semasa operasi, menyebabkan kunci tidak dapat dilepaskan seperti biasa Pada masa ini, nod B cuba mendapatkan kunci, tetapi gagal kerana nod A masih memegang kunci . Untuk menyelesaikan masalah ini, kami boleh melaksanakan penukaran kunci pintar.
Pertama, kita perlu melaksanakan mekanisme tetapan semula tamat masa kunci, iaitu selepas masa kunci tamat, kunci ditetapkan semula kepada keadaan tersedia. Ini boleh dicapai melalui tugas yang dijadualkan. Kedua, kita perlu merekodkan pemegang kunci Apabila situasi tidak normal berlaku, kunci pemegang boleh dilepaskan secara manual. Akhir sekali, kita perlu melaksanakan mekanisme pensuisan kunci, iaitu, apabila nod yang memegang kunci gagal, nod lain boleh bertukar secara automatik kepada pemegang kunci.
Untuk pelaksanaan khusus, sila rujuk kod contoh berikut:
class RedisLock { protected $redis; protected $lockKey = 'distributed_lock'; protected $timeout = 30; // 默认锁超时时间30s // 锁的持有者 protected $holder; // 获取锁的时间戳,用于超时释放锁 protected $lockTime; function __construct(){ $this->redis = new Redis(); $this->redis->connect('127.0.0.1', 6379); } function getRedisClient(){ return $this->redis; } function setLock($key = ''){ if(empty($key)){ $key = $this->lockKey; }else{ $key = $this->lockKey . '_' . $key; // 如果有传入锁键名,则拼接上前缀方便管理 } $timeout = $this->timeout; // 检查锁是否已被其他节点持有 if($lockTime = $this->redis->get($key)){ // 计算锁的剩余时间 $remainTime = $lockTime + $timeout - time(); // 如果锁剩余时间大于0,则表示其他节点持有锁 if($remainTime > 0){ return false; } } // 尝试获取锁 $result = $this->redis->set($key, time() + $timeout, ['nx', 'ex' => $timeout]); if ($result){ $this->holder = $key; $this->lockTime = time() + $timeout; return true; } return false; } function unlock($key = ''){ if(empty($key)){ $key = $this->lockKey; }else{ $key = $this->lockKey . '_' . $key; // 如果有传入锁键名,则拼接上前缀方便管理 } if($this->holder != $key){ return false; } return $this->redis->del($key); } // 定时任务,每隔一段时间检查锁的持有者是否存活,如果不存活,则尝试切换为当前节点 function timeoutReset(){ while(true){ if(time() > $this->lockTime){ $this->redis->set($this->holder, '', ['nx', 'ex' => 1]); } $this->holder = $this->redis->get($this->lockKey); if(!$this->holder){ $this->setLock(); } sleep(1); // 每个一秒执行一次 } } }
Perkara di atas melaksanakan penukaran kunci pintar. Jika nod A gagal, nod lain akan bertukar secara automatik kepada pemegang kunci selepas masa kunci tamat. Mekanisme ini memastikan ketersediaan tinggi dan kebolehpercayaan kunci yang diedarkan.
4. Ringkasan
Artikel ini memperkenalkan cara menggunakan Redis untuk melaksanakan kunci teragih dan melaksanakan mekanisme penukaran kunci pintar. Penyelesaian ini memastikan ketersediaan tinggi dan kebolehpercayaan kunci teragih dan boleh digunakan secara meluas dalam sistem teragih. Pada masa yang sama, penyelesaian ini juga boleh digunakan untuk menyelesaikan masalah lain yang memerlukan mekanisme kunci, seperti kunci baca-tulis pangkalan data, transaksi yang diedarkan, dsb.
Atas ialah kandungan terperinci Menggunakan Redis dalam PHP untuk melaksanakan penukaran pintar kunci teragih. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!