2013-04-03 3 views
9

मैं क्लाइंट के रूप में RedisOnGo + node_redis पर नोडजेएस + एक्सप्रेस + रेडिस का उपयोग कर रहा हूं। मैं बहुत सारी सहमति की उम्मीद करता हूं, इसलिए वॉच का परीक्षण करने की कोशिश कर रहा हूं। इस उदाहरण में एक्सप्रेस, केवल आवश्यक सामान नहीं होंगे।एक ग्राहक द्वारा रेडिस वॉच मल्टी एक्सेक

var redis = require("redis") 
var rc = redis.createClient(config.redis.port, config.redis.host) 

rc.auth(config.redis.hash, function(err) { 
    if (err) { 
     throw err 
    } 
}) 

rc.on('ready', function() { 
    rc.set("inc",0) 
    for(var i=1;i<=10;i++){ 
     rc.watch("inc") 
     rc.get("inc",function(err,data){ 
      var multi = rc.multi() 
      data++ // I do know I can use rc.incr(), this is just for example 
      multi.set("inc",data) 
      multi.exec(function(err,replies){ 
       console.log(replies) 
      }) 
     }) 
    } 
}) 

उम्मीद परिणाम: कार्यकारी कॉलबैक में एन त्रुटियों हो रही है और अंत में हो रही "इंक" चर = 10-एन।

अप्रत्याशित परिणाम: कार्यकारी कॉलबैक में 0 त्रुटियों हो रही लेकिन अंत में हो रही "इंक" चर = 1.

घड़ी मेरी कोड के साथ काम नहीं करता।

मुझे यह धागा redis and watch + multi allows concurrent users मिला है। वे कहते हैं कि यह केवल रेडिस क्लाइंट की वजह से है।

तब मुझे यह धागा Should I create a new Redis client for each connection? मिला। वे कहते हैं कि प्रत्येक लेनदेन के लिए एक नया ग्राहक उत्पन्न करना "निश्चित रूप से अनुशंसित नहीं है"। मै खो गया हूँ।

कृपया यह भी ध्यान दें कि मुझे Redis सर्वर को प्रमाणित करना है। अग्रिम में धन्यवाद!

संस्करण 1:

मैं हर घड़ी बहु-EXEC यात्रा से पहले एक नए ग्राहक संबंध बनाने के द्वारा यह स्थानीय Redis उदाहरण का उपयोग करते हुए (तो मैं client.auth उपयोग न करें) काम करने के लिए सक्षम था। यह सुनिश्चित नहीं है कि यह अच्छा है, लेकिन परिणाम अब 100% सटीक हैं।

संस्करण 2 यह काम करता है, तो मैं हर घड़ी बहु-EXEC यात्रा से पहले एक नए ग्राहक संबंध बनाने और उसके बाद client.auth करते हैं और client.on के लिए प्रतीक्षा किए गए।

प्रश्न अभी भी मौजूद है, क्या यह ठीक है कि मैं प्रत्येक पुनरावृत्ति के लिए नए क्लाइंट कनेक्शन बना सकता हूं?

उत्तर

17

आपका परिणाम पूरी तरह से अनुमानित है। और ठीक है तो।

ध्यान रखें - node.js एक थ्रेड एप्लिकेशन है। Node.js एसिंक्रोनस इनपुट-आउटपुट का उपयोग करते हैं, लेकिन कमांड को सख्ती से अनुक्रमिक "अनुरोध-प्रतिक्रिया" में भेजा जाना चाहिए। इसलिए आपके कोड और आपके अनुरोधों ने सख्ती से समानांतर निष्पादित किया है जबकि आप Redis सर्वर से केवल एक कनेक्शन का उपयोग कर रहे हैं। अपने कोड में

देखो:

rc.on('ready', function() { 
    rc.set("inc",0) 
    for(var i = 1; i <= 10; i++){ 
     rc.watch("inc") 
     //10 times row by row call get function. It`s realy means that your written 
     //in an asynchronous style code executed strict in series. You are using just 
     //one connection - so all command would be executed one by one. 
     rc.get("inc",function(err,data){ 
      //Your data variable data = 0 for each if request. 
      var multi = rc.multi() 
      data++ //This operation is not atomic for redis so your always has data = 1 
      multi.set("inc",data) //and set it 
      multi.exec(function(err,replies){ 
       console.log(replies) 
      }) 
     }) 
    } 
}) 

इस इस कदम कर इस बात की पुष्टि करने के लिए:

  1. कनेक्ट Redis और monitor आदेश पर अमल करने के लिए।
  2. अपने Node.js भागो आवेदन

उत्पादन

SET inc 0 
    WATCH inc 

    GET inc 
    .... get command more 9 times 

    MULTI 
    SET inc 1 
    EXEC 
    .... command block more 9 times 

तो हो सकता है कि आप वास्तव में परिणाम है कि आप ऊपर लिखा मिलता है: "कार्यकारी कॉलबैक में 0 त्रुटियों हो रही लेकिन अंत में हो रही" इंक "चर = 1."।

क्या यह ठीक है कि आप प्रत्येक पुनरावृत्ति के लिए नए क्लाइंट कनेक्शन बनाते हैं?

इस नमूने के लिए - हाँ, यह आपकी समस्या हल करता है। सामान्य रूप से - यह इस बात पर निर्भर करता है कि आप कितने "समवर्ती" क्वेरी को चलाने के लिए चाहते हैं। रेडिस अभी भी एक थ्रेडेड है इसलिए यह "समवर्ती" का मतलब रेडिस इंजन को समवर्ती कमांड बैच का एकमात्र तरीका है।

उदाहरण के लिए

, उपयोग 2 कनेक्शन monitor कुछ इस तरह दे सकता है यदि:

1 SET inc 0 //from 1st connection 
2 WATCH inc //from 1st connection 
3 SET inc 0 //from 2nd connection    
4 GET inc //from 1nd connection    
5 WATCH int //from 2nd connection  
6 GET inc //from 2nd connection     
7 MULTI //from 1st connection   
8 SET inc 1 //from 1st connection  
9 MULTI //from 2nd connection   
10 SET inc 1 //from 2nd connection   
11 EXEC //from 1st failed becouse of 2nd connection SET inc 0 (line 3) 
     //was executed after WATCH (line 2) 
12 EXEC //success becouse of MULTI from 1st connection was failed and SET inc 1 from first 
     //connection was not executed 

-------------------------------------------------------------------------------> time 
       | | | | |  |  | | |  | |   | 
connection 1 set watch | get |  | multi set |  | exec(fail) | 
connection 2   set watch get   multi set   exec 

इसकी बहुत महत्वपूर्ण समझने के लिए redis अपने आदेश पर अमल। रेडिस एकल थ्रेडेड है, सभी कनेक्शन से सभी कमांड एक पंक्ति में एक-एक करके निष्पादित होते हैं। रेडिस गारंटी नहीं देता है कि एक कनेक्शन से कमांड को एक पंक्ति में निष्पादित किया जाएगा (यदि यहां कोई अन्य कनेक्शन मौजूद है) तो आपको यह सुनिश्चित करना चाहिए कि आपके आदेशों ने एक ब्लॉक को निष्पादित किया है (यदि इसकी आवश्यकता है)। लेकिन क्यों वॉच की जरूरत है? उपरोक्त मेरे redis आदेशों को देखो। आप देख सकते हैं कि विभिन्न कनेक्शन से आने वाले कमांड मिश्रित हैं। और देखो आप इसे प्रबंधित करने की अनुमति देते हैं।

यह खूबसूरती से documentation में समझाया गया है। कृपया इसे पढ़ें!

+0

धन्यवाद, आपका जवाब काफी व्याख्यात्मक हो रहा है और आप मेरे सवाल का सही समझ लिया है। यदि 2 दिनों में कोई और जवाब नहीं है, तो बक्षीस तुम्हारा है। – igorpavlov

1

मुझे आपका प्रश्न अंत में मिला।

यदि आप समेकन के लिए वॉच का परीक्षण करना चाहते हैं, तो मुझे लगता है कि आपको अपना कोड बदलना होगा। जैसा कि हम जानते हैं। वॉच केवल मूल्य बदलने की निगरानी करता है, मूल्य संचालन नहीं प्राप्त करता है। इसलिए आपके वर्तमान कोड में, आपके सभी get कमांड को सफलतापूर्वक निष्पादित किया जाएगा और 0 प्राप्त होगा, फिर वे inc1 पर सेट करेंगे। सभी सेट मान समान हैं (1), इसलिए घड़ी विफल नहीं होगी।

मामले में, हमें यह सुनिश्चित करने की आवश्यकता है कि न केवल write ऑपरेशन सुरक्षित है, लेकिन read भी। inc सेट करने से पहले, आपको watch की आवश्यकता है और निराशावादी लॉक के रूप में एक और कुंजी संशोधित करें, और फिर हम inc प्राप्त और बदल सकते हैं। इस तरह, यह आपकी उम्मीद सुनिश्चित करेगा।

rc.set("inc",0) 
for(var i=1;i<=10;i++){ 
    rc.watch("inc-lock") 
    rc.get("inc",function(err,data){ 
     var multi = rc.multi() 
     data++ 
     multi.incr("inc-lock") 
     multi.set("inc",data) 
     multi.exec(function(err,replies){ 
      console.log(replies) 
     }) 
    }) 
} 

मैंने इसे अपने पीसी में परीक्षण किया।

[2013-11-26 18: 51: ०९.३८९] [जानकारी] कंसोल - [1, 'ठीक है']

[2013-11-26 18: 51: ०९.३९०] [जानकारी] सांत्वना - [2, 'ठीक है']

[2013-11-26 18: 51: ०९.३९०] [जानकारी] कंसोल - [3, 'ठीक है']

[2013-11-26 18:51: 09.3 9 0] [INFO] कंसोल - [4, 'ओके']

[2013-11-26 18: 51: 09.3 9 1] [INFO] कंसोल - [5, 'ठीक']

,210

[2013-11-26 18: 51: ०९.३९१] [जानकारी] कंसोल - [6, 'ठीक है']

[2013-11-26 18: 51: ०९.३९२] [जानकारी] सांत्वना - [7 , 'ओके']

[2013-11-26 18:51:09।392] [जानकारी] कंसोल - [8, 'ठीक है']

[2013-11-26 18: 51: ०९.३९३] [जानकारी] सांत्वना - [9, 'ठीक है']

[2013-11 -26 18: 51: ०९.३९३] [जानकारी] कंसोल - [10, 'ठीक है']

+0

उत्तर के लिए धन्यवाद। हालांकि, यह मेरी समस्या को कवर नहीं करता है। मैं रेडिस की क्यूइंग प्रक्रिया को समझता हूं, यहां समस्या काफी सरल है हालांकि: मेरे पास एक एकल नोड प्रक्रिया है और यदि मैं एप्लिकेशन की शुरुआत में एक बार रेडिस से कनेक्ट करता हूं और सभी कनेक्शनों के लिए इस कनेक्शन का उपयोग करने का प्रयास करता हूं - वॉच नहीं करता है काम करने लगते हैं। अगर मैं हर बार नया लेनदेन करता हूं तो मैं "लेनदेन" करता हूं, वॉच काम करता है और वास्तव में कुंजी देखता है। लेकिन जब भी मुझे इसका अनुरोध करने की ज़रूरत होती है तो मैं रेडिस से कनेक्ट नहीं करना चाहता हूं। यही दिक्कत है। – igorpavlov

+0

मैंने आपको प्राप्त किया और मेरा जवाब अपडेट किया, कृपया इसे जांचें। –

+0

आपके समय के लिए फिर से धन्यवाद, लेकिन फिर भी, सही नहीं है। कोड में मैंने एक टिप्पणी लिखा है "// मुझे पता है कि मैं rc.incr() का उपयोग कर सकता हूं, यह सिर्फ उदाहरण के लिए है"। मुझे पता है incr() एक परमाणु ऑपरेशन है। लेकिन, इस कोड के अंदर जीईटी-> एसईटी जैसे कई गैर-परमाणु संचालन हो सकते हैं। इसके अलावा, आपको incr() के साथ वॉच का उपयोग करने की आवश्यकता नहीं है। – igorpavlov

1

आप लेन-देन/परमाणु बहु संचालन उपयोग करना चाहते हैं, लेकिन आप जहां तक ​​एक साझा कनेक्शन का उपयोग कर ऐसा करने के लिए, चाहते हैं मुझे पता है कि आपका एकमात्र विकल्प LUA का उपयोग कर रहा है।

मैं कई चीजों के लिए लाल रंग के भीतर लुआ स्क्रिप्टिंग का उपयोग करता हूं, और LUA के साथ यह बात पूरी स्क्रिप्ट परमाणु रूप से निष्पादित होगी, जो काफी सुविधाजनक है। आपको जागरूक होना चाहिए हालांकि इसका मतलब है कि यदि आपके पास धीमी लूए स्क्रिप्ट है तो आप अपने सर्वर का उपयोग करने वाले हर किसी के लिए लाल धीमा कर रहे हैं।

इसके अलावा, जब आप विभिन्न चाबियों पर काम कर सकते हैं तो LUA का उपयोग करते समय भी सावधान रहें, अगर आप अपनी स्क्रिप्ट में एक से अधिक कुंजी का उपयोग करते हैं तो आप Redis क्लस्टर को रिलीज़ होने के बाद उपयोग नहीं कर पाएंगे। यह क्लस्टर का उपयोग करते समय, कुंजी को विभिन्न Redis प्रक्रियाओं में वितरित किया जाएगा, इसलिए आपके LUA स्क्रिप्ट को उन सभी को एक सर्वर पर एक्सेस नहीं हो सकता है।

किसी भी मामले में, मल्टी जारी करते समय रेडिस क्लस्टर के साथ समस्या समान होगी, क्योंकि बहु को क्लस्टर पर अलग-अलग कुंजी सेट करने की अनुमति नहीं दी जाएगी।

चीयर्स,

जे

+0

LUA निश्चित रूप से यहां एक समाधान है, धन्यवाद। सुनिश्चित नहीं है कि अब कौन सा बक्षीस प्राप्त करेगा =) – igorpavlov

संबंधित मुद्दे