Rumah  >  Artikel  >  pangkalan data  >  Artikel yang menerangkan secara terperinci cara menggunakan Redis untuk melaksanakan kunci teragih

Artikel yang menerangkan secara terperinci cara menggunakan Redis untuk melaksanakan kunci teragih

WBOY
WBOYke hadapan
2022-09-07 14:18:182102semak imbas

Pembelajaran yang disyorkan: Tutorial video Redis

1. Apakah itu kunci teragih

Bila Apabila kami menulis kod berbilang utas, utas yang berbeza mungkin bersaing untuk mendapatkan sumber Untuk mengelakkan ralat yang disebabkan oleh persaingan sumber, kami akan mengunci sumber Hanya utas yang telah memperoleh kunci boleh terus dilaksanakan.

Kunci dalam proses pada asasnya ialah pembolehubah dalam ingatan Apabila benang menjalankan operasi untuk memohon kunci, jika ia berjaya menetapkan nilai pembolehubah yang mewakili kunci kepada 1, ini bermakna. kunci telah diperoleh.

Apa yang kita bincangkan di atas ialah kunci antara benang yang berbeza dalam proses pelayan Kunci ini diletakkan dalam ingatan, dan untuk aplikasi yang diedarkan Katakan, aplikasi yang berbeza (proses atau benang) digunakan pada pelayan yang berbeza, jadi kunci tidak boleh diwakili oleh pembolehubah dalam ingatan.

Memandangkan kunci boleh diwakili oleh ruang memori yang dikongsi pada pelayan, untuk aplikasi yang diedarkan, sistem storan boleh dikongsi untuk menyimpan kunci yang dikongsi Ini adalah kunci yang diedarkan , Redis dilaksanakan dengan sangat pantas dan sangat sesuai sebagai sistem storan kongsi untuk melaksanakan kunci teragih.

2. Gunakan Redis untuk melaksanakan kunci yang diedarkan

Untuk kunci, sebenarnya hanya terdapat dua operasi, mengunci dan melepaskan kunci Mari lihat di bawah lihat bagaimana untuk mencapainya melalui Redis?

2.1 Perintah mengunci

Redissetnx akan menentukan sama ada nilai kunci wujud Jika wujud, tiada operasi akan dilakukan dan 0 akan dilakukan dikembalikan. Jika ia wujud, buat dan tetapkan nilai, dan kembalikan 1, supaya kita boleh melaksanakan setnx untuk menetapkan nilai untuk kunci kunci wakil Jika tetapan berjaya, ini bermakna kunci itu diperolehi. kunci tidak boleh diperolehi.

# 使用key为lock来表示一个锁
setnx lock 1

2.2 Lepaskan kunci

Selepas menjalankan operasi, apabila anda ingin melepaskan kunci, hanya padamkan nilai kunci Redis dalam lock supaya proses lain boleh menetapkan semula dan mendapatkan kunci melalui perintah setnx.

# 释放锁
del lock

Melalui dua arahan di atas, kami telah melaksanakan kunci teragih mudah, tetapi terdapat masalah di sini: jika proses dikunci melalui perintah setnx, ralat berlaku semasa operasi tertentu. Jika tiada cara untuk melepaskan kunci dalam masa, maka proses lain tidak akan dapat mendapatkan kunci, dan sistem tidak akan dapat meneruskan pelaksanaan Cara untuk menyelesaikan masalah ini adalah dengan menetapkan tempoh sah untuk kunci , dan selepas tempoh sah ini, kunci akan dilepaskan secara automatik.

2.3 Tetapkan tempoh sah untuk kunci

Sangat mudah untuk menetapkan tempoh sah untuk kunci Hanya gunakan perintah Redis expire , seperti:

# 加锁
setnx lock 1 
# 给锁设置10s有效期
expire lock 10

Walau bagaimanapun, masalah lain timbul sekarang jika kita menetapkan kunci dan proses digantung sebelum melaksanakan perintah expire, maka expire tidak akan berjaya dilaksanakan dan kunci akan. tidak dilepaskan, jadi kita mesti memastikan bahawa kedua-dua arahan di atas dilaksanakan bersama-sama.

mempunyai dua kaedah, satu ialah menggunakan skrip yang ditulis dalam bahasa LUA, dan satu lagi ialah menggunakan perintah Redis set Perintah set diikuti oleh nx parameter, dan kesan pelaksanaan adalah Ia konsisten dengan setnx, dan perintah set boleh digunakan dengan parameter ex untuk menetapkan masa tamat tempoh, jadi kita boleh menggunakan perintah set untuk bergabung setnx dan expire bersama-sama, supaya pelaksanaan boleh dijamin Ia atom.

# 判断是否键值是否存在,ex后面跟着的是键值的有效期,10s
set lock 1 nx ex 10

Setelah menyelesaikan masalah penguncian yang berkesan, kini mari kita lihat masalah lain.

Seperti yang ditunjukkan dalam gambar di atas, kini terdapat proses A, B dan C pada tiga pelayan berbeza yang perlu mendapatkan kunci apabila melakukan operasi tertentu Kunci mesti dilepaskan selepas pelaksanaan.

现在的情况是进程A执行第2步时卡顿了(上面绿色区域所示),且时间超出了锁有效期,所以进程A设置的锁自动释放了,这时候进程B获得了锁,并开始执行操作,但由于进程A只是卡顿了而已,所以会继续执行的时候,在第3步的时候会手动释放锁,但是这个时候,锁由线程B所拥有,也就是说进程A删除的不是自己的锁,而进程B的锁,这时候进程B还没执行完,但锁被释放后,进程C可以加锁,也就是说由于进程A卡顿释放错了锁,导致进程B和进程C可以同时获得锁

怎么避免这种情况呢?如何区分其他进程的锁,避免删除其他进程的锁呢?答案就是每个进程在加锁的时候,给锁设置一个唯一值,并在释放锁的时候,判断是不是自己设置的锁。

2.4 给锁设置唯一值

给锁设置唯一值的时候,一样是使用set命令,唯一的不同是将键值1改为一个随机生成的唯一值,比如uuid。

 # rand_uid表示唯一id
set lock rand_id nx ex 10

当锁里的值由进程设置后,释放锁的时候,就需要判断锁是不是自己的,步骤如下:

  • 通过Redisget命令获得锁的值
  • 根据获得的值,判断锁是不是自己设置的
  • 如果是,通过del命令释放锁。

此时我们看到,释放锁需要执行三个操作,如果三个操作依次执行的话,是没有办法保证原子性的,比如进程A在执行到第2步后,准备开始执行del命令时,而锁由时有效期到了,被自动释放了,并被其他服务器上的进程B获得锁,但这时候线程A执行del还是把线程B的锁给删掉了。

解决这个问题的办法就是保证上述三个操作执行的原子性,即在执行释放锁的三个操作中,其他进程不可以获得锁,想要做到这一点,需要使用到LUA脚本。

2.5 通过LUA脚本实现释放锁的原子性

Redis支持LUA脚本,LUA脚里的代码执行的时候,其他客户端的请求不会被执行,这样可以保证原子性操作,所以我们可以使用下面脚本进行锁的释放:

if redis.call("get",KEYS[1]) == ARGV[1] then 
  return redis.call("del",KEYS[1])
else 
  return 0
end

将上述脚本保存为脚本后,可以调用Redis客户端命令redis-cli来执行,如下:

# lock为key,rand_id表示key里保存的值
redis-cli --eval unlock.lua lock , rand_id

推荐学习:Redis视频教程

Atas ialah kandungan terperinci Artikel yang menerangkan secara terperinci cara menggunakan Redis untuk melaksanakan kunci teragih. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:jb51.net. Jika ada pelanggaran, sila hubungi admin@php.cn Padam