Apakah yang perlu anda perhatikan semasa melaksanakan kunci teragih dalam Redis? Artikel berikut akan meringkaskan dan berkongsi dengan anda beberapa perkara yang perlu diberi perhatian apabila menggunakan Redis sebagai kunci yang diedarkan saya harap ia akan membantu anda!
Redis melaksanakan kunci teragih
Baru-baru ini saya melihat satu artikel sambil melihat kunci yang diedarkan Artikel yang bagus, diproses khas untuk pemahaman saya sendiri:
Tiga elemen teras pelaksanaan kunci yang diedarkan Redis:
1 Mengunci
Cara paling mudah ialah menggunakan perintah setnx. Kuncinya ialah pengecam unik kunci, yang dinamakan mengikut perniagaan Nilai ialah ID utas urutan semasa. [Cadangan berkaitan: Tutorial video Redis]
Contohnya, jika anda ingin mengunci aktiviti jualan kilat produk, anda boleh menamakan kunci "lock_sale_ID". Dan apakah nilai yang ditetapkan? Kita boleh menetapkannya buat sementara waktu kepada 1. Kod pseudo untuk mengunci adalah seperti berikut:
setnx(key, 1)Apabila thread melaksanakan setnx dan mengembalikan 1, ini bermakna kunci itu tidak wujud dan benang berjaya memperolehnya Kunci, apabila utas lain melaksanakan setnx dan mengembalikan 0, ini bermakna kunci itu sudah wujud dan utas gagal meraih kunci.
2. Membuka kunci
Jika sesuatu dikunci, ia mesti dibuka. Apabila benang yang memperoleh kunci menyelesaikan tugasnya, ia perlu melepaskan kunci supaya benang lain boleh masuk. Cara paling mudah untuk melepaskan kunci adalah dengan melaksanakan arahan del Kod pseudo adalah seperti berikut:
del (kunci) Selepas. melepaskan kunci, benang lain Anda boleh terus melaksanakan perintah setnx untuk mendapatkan kunci.
3. Tamat masa kunci
Apakah maksud tamat masa kunci? Jika benang yang memperoleh kunci mati semasa melaksanakan tugas dan tidak mempunyai masa untuk melepaskan kunci secara eksplisit, sumber akan dikunci selama-lamanya dan utas lain tidak akan dapat masuk lagi.
Oleh itu, kunci setnx mesti menetapkan tempoh tamat masa untuk memastikan walaupun ia tidak dilepaskan secara eksplisit, kunci akan dilepaskan secara automatik selepas tempoh masa tertentu. setnx tidak menyokong parameter tamat masa, jadi arahan tambahan diperlukan kod pseudo adalah seperti berikut:
tamat tempoh (kunci, 30) Diambil bersama, langkah ketiga. pelaksanaan kunci teragih kami Versi pertama pseudokod adalah seperti berikut:
if(setnx(key,1) == 1){ expire(key,30) try { do something ...... }catch() { } finally { del(key) } }
Oleh kerana terdapat tiga masalah maut dalam pseudokod di atas:
1 ketidakatoman setnx dan tamat tempoh
Bayangkan senario yang melampau apabila benang melaksanakan setnx, ia berjaya memperoleh kunci: setnx baru sahaja berjaya dilaksanakan dan telah. belum sempat melaksanakan perintah tamat tempoh Nod 1 Duang Tiba-tiba menutup telefon.if(setnx(key,1) == 1){ //此处挂掉了..... expire(key,30) try { do something ...... }catch() { } finally { del(key) } }
Redis 2.6.12 atau lebih tinggi menambah parameter pilihan pada arahan yang ditetapkan adalah seperti berikut: set (kunci, 1, 30, NX). supaya Boleh menggantikan arahan setnx .
2. Menggunakan del selepas tamat masa mengakibatkan secara tidak sengaja memadamkan kunci urutan lain
Satu lagi senario melampau, jika benang berjaya mendapatkan kunci dan tamat masa ditetapkan kepada 30 saat. Jika atas sebab tertentu benang A dijalankan dengan sangat perlahan dan belum selesai dilaksanakan selepas 30 saat, kunci akan dilepaskan secara automatik apabila tamat tempoh dan benang B akan memperoleh kunci. Selepas itu, utas A menyelesaikan tugasan dan utas A kemudian melaksanakan arahan del untuk melepaskan kunci. Tetapi pada masa ini, utas B belum selesai melaksanakanThread A sebenarnya telah memadamkan kunci yang ditambahkan oleh utas B .
Bagaimana untuk mengelakkan situasi ini? Anda boleh membuat pertimbangan sebelum del melepaskan kunci untuk mengesahkan sama ada kunci semasa ialah kunci yang ditambahkan oleh anda sendiri. Bagi pelaksanaan khusus, anda boleh menggunakan ID utas semasa sebagai nilai semasa mengunci dan mengesahkan sama ada nilai yang sepadan dengan kunci itu ialah ID urutan anda sendiri sebelum memadamkannya.加锁: String threadId = Thread.currentThread().getId() set(key,threadId ,30,NX) doSomething..... 解锁: if(threadId .equals(redisClient.get(key))){ del(key) }
jika penghakiman dan pelepasan kunci adalah dua operasi bebas, bukan atom.
Kami semua adalah pengaturcara yang mengejar kesempurnaan, jadi bahagian ini perlu dilaksanakan menggunakan skrip Lua:String luaScript = 'if redis .call('get', KEYS[1]) == ARGV[1] kemudian kembalikan redis.call('del', KEYS[1]) else return 0 end' ;
redisClient.eval(luaScript , Collections.singletonList(key) , Collections.singletonList(threadId));
Dengan cara ini, proses pengesahan dan pemadaman adalah operasi atom.3. Kemungkinan konkurensi
还是刚才第二点所描述的场景,虽然我们避免了线程A误删掉key的情况,但是同一时间有A,B两个线程在访问代码块,仍然是不完美的。
怎么办呢?我们可以让获得锁的线程开启一个守护线程,用来给快要过期的锁“续航”。
当过去了29秒,线程A还没执行完,这时候守护线程会执行expire指令,为这把锁“续命”20秒。守护线程从第29秒开始执行,每20秒执行一次。
当线程A执行完任务,会显式关掉守护线程。
另一种情况,如果节点1 忽然断电,由于线程A和守护线程在同一个进程,守护线程也会停下。这把锁到了超时的时候,没人给它续命,也就自动释放了。
首页top 10, 由数据库加载到memcache缓存n分钟
微博中名人的content cache, 一旦不存在会大量请求不能命中并加载数据库
需要执行多个IO操作生成的数据存在cache中, 比如查询db多次
问题
在大并发的场合,当cache失效时,大量并发同时取不到cache,会同一瞬间去访问db并回设cache,可能会给系统带来潜在的超负荷风险。我们曾经在线上系统出现过类似故障。
解决方法
if (memcache.get(key) == null) { // 3 min timeout to avoid mutex holder crash if (memcache.add(key_mutex, 3 * 60 * 1000) == true) { value = db.get(key); memcache.set(key, value); memcache.delete(key_mutex); } else { sleep(50); retry(); } }
在load db之前先add一个mutex key, mutex key add成功之后再去做加载db, 如果add失败则sleep之后重试读取原cache数据。为了防止死锁,mutex key也需要设置过期时间。伪代码如下
Zookeeper的数据存储结构就像一棵树,这棵树由节点组成,这种节点叫做Znode
。
Znode
分为四种类型:
持久节点
(PERSISTENT)默认的节点类型。创建节点的客户端与zookeeper断开连接后,该节点依旧存在 。
持久节点顺序节点
(PERSISTENT_SEQUENTIAL)所谓顺序节点,就是在创建节点时,Zookeeper根据创建的时间顺序给该节点名称进行编号:
临时节点
(EPHEMERAL)和持久节点相反,当创建节点的客户端与zookeeper断开连接后,临时节点会被删除:
临时顺序节点
(EPHEMERAL_SEQUENTIAL)顾名思义,临时顺序节点结合和临时节点和顺序节点的特点:在创建节点时,Zookeeper根据创建的时间顺序给该节点名称进行编号;当创建节点的客户端与zookeeper断开连接后,临时节点会被删除。
Zookeeper分布式锁恰恰应用了临时顺序节点。具体如何实现呢?让我们来看一看详细步骤:
首先,在Zookeeper当中创建一个持久节点ParentLock
。当第一个客户端想要获得锁时,需要在ParentLock
这个节点下面创建一个临时顺序节点 Lock1
。
之后,Client1
查找ParentLock
下面所有的临时顺序节点并排序,判断自己所创建的节点Lock1
是不是顺序最靠前的一个。如果是第一个节点,则成功获得锁。
这时候,如果再有一个客户端 Client2
前来获取锁,则在ParentLock
下载再创建一个临时顺序节点Lock2
。
Client2
查找ParentLock
下面所有的临时顺序节点并排序,判断自己所创建的节点Lock2
是不是顺序最靠前的一个,结果发现节点Lock2
并不是最小的。
Jadi, Client2
mendaftarkan Lock1
dengan nod Watcher
yang hanya berkedudukan lebih tinggi daripadanya, untuk memantau sama ada nod Lock1
wujud. Ini bermakna Client2
gagal mengambil kunci dan memasuki keadaan menunggu.
Pada masa ini, jika pelanggan lain Client3
datang untuk memperoleh kunci, muat turun dan buat nod jujukan sementara ParentLock
dalam Lock3
.
Client3
Cari semua nod jujukan sementara di bawah ParentLock
dan isikannya dan nilai sama ada nod Lock3
yang anda cipta adalah yang mempunyai susunan tertinggi. Hasilnya Juga didapati bahawa nod Lock3
bukanlah yang terkecil.
Jadi, Client3
mendaftarkan Lock2
dengan nod Watcher
yang hanya berkedudukan lebih tinggi daripadanya, untuk memantau sama ada nod Lock2
wujud. Ini bermakna Client3
juga gagal mengambil kunci dan memasuki keadaan menunggu.
Dengan cara ini, Client1
mendapat kunci, Client2
memantau Lock1
dan Client3
memantau Lock2
. Ini hanya membentuk baris gilir menunggu, sama seperti ReentrantLock
yang AQS(AbstractQueuedSynchronizer)
bergantung pada Java.
Terdapat dua situasi untuk melepaskan kunci:
1. Apabila tugasan selesai, klien memaparkan keluaran
Apabila tugasan selesai, Client1
akan memaparkan arahan untuk memanggil nod padam Lock1
.
2 Semasa pelaksanaan tugas, pelanggan ranap
Mendapat kunciClient1
Semasa pelaksanaan tugas, jika Duang ranap, maka Sambungan ke pelayan Zookeeper akan diputuskan. Mengikut ciri nod sementara, nod yang berkaitan Lock1
akan dipadamkan secara automatik.
Memandangkan Client2
sentiasa memantau status kewujudan Lock1
, apabila nod Lock1
dipadamkan, Client2
akan menerima pemberitahuan serta-merta. Pada masa ini, Client2
akan menanyakan semua nod di bawah ParentLock
sekali lagi untuk mengesahkan sama ada nod Lock2
yang dibuat dengan sendirinya ialah nod terkecil pada masa ini. Jika ia adalah yang terkecil, maka Client2
secara semula jadi memperoleh kunci.
Begitu juga, jika Client2
turut memadamkan nod Lock2
disebabkan penyiapan tugas atau ranap nod, maka Cient3
akan menerima pemberitahuan.
Akhirnya, Client3
berjaya mendapatkan kunci.
Jadual di bawah Meringkaskan kelebihan dan kekurangan kunci yang diedarkan Zookeeper dan Redis:
Untuk lebih banyak pengetahuan berkaitan pengaturcaraan, sila lawati: Pengenalan kepada Pengaturcaraan ! !
Atas ialah kandungan terperinci Apakah yang perlu kita perhatikan semasa melaksanakan kunci teragih dalam Redis? [Ringkasan perkara yang memerlukan perhatian]. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!