Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Redis

การเขียนสคริปต์ Master Redis Lua:คู่มือปฏิบัติเพื่อเพิ่มประสิทธิภาพ

การเขียนสคริปต์ Master Redis Lua:คู่มือปฏิบัติเพื่อเพิ่มประสิทธิภาพ

โดย อังเดร เชอร์นิคอฟ

Redis เป็นตารางในหน่วยความจำยอดนิยมที่ใช้สำหรับการสื่อสารระหว่างกระบวนการและการจัดเก็บข้อมูล คุณอาจเคยได้ยินมาว่ามันให้คุณเรียกใช้สคริปต์ Lua ได้ แต่คุณก็ยังไม่แน่ใจว่าทำไม หากฟังดูเหมือนคุณ โปรดอ่านต่อ

การเขียนสคริปต์ Master Redis Lua:คู่มือปฏิบัติเพื่อเพิ่มประสิทธิภาพ

ข้อกำหนดเบื้องต้น

คุณควรติดตั้ง Redis บนระบบของคุณเพื่อปฏิบัติตามคำแนะนำนี้ การตรวจสอบการอ้างอิงคำสั่ง Redis ขณะอ่านอาจเป็นประโยชน์

เหตุใดฉันจึงต้องมีสคริปต์ Lua

กล่าวโดยย่อ:ประสิทธิภาพเพิ่มขึ้น งานส่วนใหญ่ที่คุณทำใน Redis เกี่ยวข้องกับหลายขั้นตอน แทนที่จะทำตามขั้นตอนเหล่านี้ในภาษาของแอปพลิเคชันของคุณ คุณสามารถทำได้ภายใน Redis กับ Lua

  • ซึ่งอาจส่งผลให้ประสิทธิภาพดีขึ้น
  • นอกจากนี้ ขั้นตอนทั้งหมดภายในสคริปต์จะดำเนินการในลักษณะอะตอมมิก ไม่มีคำสั่ง Redis อื่นใดที่สามารถทำงานได้ในขณะที่สคริปต์กำลังดำเนินการอยู่

ตัวอย่างเช่น ฉันใช้สคริปต์ Lua เพื่อเปลี่ยนสตริง JSON ที่จัดเก็บไว้ใน Redis ฉันอธิบายรายละเอียดนี้ในตอนท้ายของบทความนี้

แต่ฉันไม่รู้จักลัวะเลย

การเขียนสคริปต์ Master Redis Lua:คู่มือปฏิบัติเพื่อเพิ่มประสิทธิภาพ คนที่ไม่รู้จักลัวะเลย

ไม่ต้องกังวล Lua เข้าใจได้ไม่ยากนัก หากคุณรู้ภาษาใด ๆ ของตระกูล C คุณควรจะโอเคกับ Lua นอกจากนี้ ฉันกำลังยกตัวอย่างการทำงานในบทความนี้

แสดงตัวอย่าง

เริ่มต้นด้วยการเรียกใช้สคริปต์ผ่าน redis-cli . เริ่มต้นด้วย:

redis-cli

ตอนนี้รันคำสั่งต่อไปนี้:

eval “redis.call(‘set’, KEYS[1], ARGV[1])” 1 key:name value

EVAL command คือสิ่งที่บอกให้ Redis รันสคริปต์ซึ่งตามมา 01 string คือสคริปต์ของเราซึ่งมีฟังก์ชันการทำงานเหมือนกับ 14 ของ Redis คำสั่ง พารามิเตอร์สามตัวตามข้อความสคริปต์:

  1. จำนวนคีย์ที่ให้มา
  2. ชื่อคีย์
  3. อาร์กิวเมนต์แรก

อาร์กิวเมนต์สคริปต์แบ่งออกเป็นสองกลุ่ม:KEYS และ ARGV .

เราระบุจำนวนคีย์ที่สคริปต์ต้องการโดยมีตัวเลขตามมาทันที ในตัวอย่างของเรา มันคือ 1 . ทันทีหลังจากหมายเลขนี้ เราต้องจัดเตรียมกุญแจเหล่านี้ทีละอัน สามารถเข้าถึงได้ในรูปแบบ KEYS ตารางภายในสคริปต์ ในกรณีของเรา จะมีค่าเดียวคือ 22 ที่ดัชนี 1 .

โปรดทราบว่าตารางที่จัดทำดัชนี Lua เริ่มต้นด้วยดัชนี 1, ไม่ 0 .

เราสามารถระบุอาร์กิวเมนต์จำนวนเท่าใดก็ได้หลังคีย์ ซึ่งจะพร้อมใช้งานในภาษา Lua เป็น ARGV ตาราง ในตัวอย่างนี้ เราระบุ ARGV รายการเดียว -อาร์กิวเมนต์:สตริง 33 . ตามที่คุณเดาแล้ว คำสั่งด้านบนจะตั้งค่าคีย์ 47 เป็นค่า 55 .

ถือเป็นแนวปฏิบัติที่ดีที่จะจัดเตรียมคีย์ที่สคริปต์ใช้เป็น KEYS และอาร์กิวเมนต์อื่นๆ ทั้งหมดเป็น ARGV . ดังนั้นคุณไม่ควรระบุ KEYS เป็น 0 จากนั้นระบุคีย์ทั้งหมดภายใน ARGV ตาราง

ตอนนี้เรามาตรวจสอบว่าสคริปต์เสร็จสมบูรณ์หรือไม่ เราจะดำเนินการนี้โดยการเรียกใช้สคริปต์อื่นซึ่งรับคีย์จาก Redis:

eval “return redis.call('get', KEYS[1])” 1 คีย์:ชื่อ

ผลลัพธ์ควรเป็น 65 ซึ่งหมายความว่าสคริปต์ก่อนหน้าตั้งค่าคีย์ 74 ได้สำเร็จ .

คุณช่วยอธิบายสคริปต์ได้ไหม

การเขียนสคริปต์ Master Redis Lua:คู่มือปฏิบัติเพื่อเพิ่มประสิทธิภาพ Doge หลังจากเห็นสคริปต์ด้านบน

สคริปต์แรกของเราประกอบด้วยคำสั่งเดียว:87 ฟังก์ชัน:

redis.call(‘set’, KEYS[1], ARGV[1])

ด้วย96 คุณสามารถดำเนินการคำสั่ง Redis ใดก็ได้ อาร์กิวเมนต์แรกคือชื่อของคำสั่งนี้ตามด้วยพารามิเตอร์ ในกรณีของ 101 คำสั่ง อาร์กิวเมนต์เหล่านี้คือ คีย์ และค่า . รองรับคำสั่ง Redis ทั้งหมด ตามเอกสารประกอบ:

Redis ใช้ล่าม Lua เดียวกันเพื่อรันคำสั่งทั้งหมด

สคริปต์ที่สองของเราทำมากกว่าการรันคำสั่งเดียวเพียงเล็กน้อย แต่ยังส่งคืนค่า:

eval “return redis.call(‘get’, KEYS[1])” 1 key:name

ทุกสิ่งที่สคริปต์ส่งคืนจะถูกส่งไปยังกระบวนการเรียก ในกรณีของเรา กระบวนการนี้คือ redis-cli และคุณจะเห็นผลลัพธ์ในหน้าต่างเทอร์มินัลของคุณ

มีอะไรซับซ้อนกว่านี้ไหม

การเขียนสคริปต์ Master Redis Lua:คู่มือปฏิบัติเพื่อเพิ่มประสิทธิภาพ บุคคลที่วางแผนจะสร้างสคริปต์ Redis ที่ซับซ้อน

ฉันเคยใช้สคริปต์ Lua เพื่อส่งคืนองค์ประกอบจากแมปแฮชตามลำดับเฉพาะ ลำดับนั้นถูกระบุโดยแฮชคีย์ที่จัดเก็บไว้ในชุดที่เรียงลำดับ

ขั้นแรกเรามาตั้งค่าข้อมูลของเราด้วยการรันคำสั่งเหล่านี้ใน redis-cli :

hmset hkeys key:1 value:1 key:2 value:2 key:3 value:3 key:4 value:4 key:5 value:5 key:6 value:6
zadd order 1 key:3 2 key:1 3 key:2

คำสั่งเหล่านี้สร้างแผนที่แฮชที่คีย์ 115 และชุดที่เรียงลำดับที่คีย์ 120 ซึ่งมีคีย์ที่เลือกจาก 131 ในลำดับเฉพาะ

คุณอาจต้องการตรวจสอบ อืมเซ็ต และ แซด อ้างอิงคำสั่งเพื่อดูรายละเอียด

มาเรียกใช้สคริปต์ต่อไปนี้:

eval “local order = redis.call(‘zrange’, KEYS[1], 0, -1); return redis.call(‘hmget’,KEYS[2],unpack(order));” 2 order hkeys

คุณควรเห็นผลลัพธ์ต่อไปนี้:

“value:3”
“value:1”
“value:2”

ซึ่งหมายความว่าเราได้รับค่าของคีย์ที่เราต้องการและอยู่ในลำดับที่ถูกต้อง

ฉันต้องระบุข้อความสคริปต์แบบเต็มเพื่อเรียกใช้หรือไม่

ไม่! Redis ช่วยให้คุณสามารถโหลดสคริปต์ล่วงหน้าลงในหน่วยความจำด้วย SCRIPT LOAD คำสั่ง:

script load “return redis.call(‘get’, KEYS[1])”

คุณควรเห็นผลลัพธ์ดังนี้:

“4e6d8fc8bb01276962cce5371fa795a7763657ae”

นี่คือแฮชเฉพาะของสคริปต์ที่คุณต้องระบุให้กับ EVALSHA คำสั่งเพื่อรันสคริปต์:

evalsha 4e6d8fc8bb01276962cce5371fa795a7763657ae 1 key:name

หมายเหตุ:คุณควรใช้ค่าจริง SHA1 แฮชที่ส่งคืนโดย โหลดสคริปต์ คำสั่ง แฮชด้านบนนี้เป็นเพียงตัวอย่างเท่านั้น

คุณพูดถึงอะไรเกี่ยวกับการเปลี่ยน JSON

บางครั้งผู้คนเก็บวัตถุ JSON ไว้ใน Redis ไม่ว่าจะเป็นความคิดที่ดีหรือไม่ก็เป็นอีกเรื่องหนึ่ง แต่ในทางปฏิบัติ สิ่งนี้เกิดขึ้นบ่อยครั้ง

หากคุณต้องเปลี่ยนคีย์ในออบเจ็กต์ JSON นี้ คุณจะต้องรับคีย์จาก Redis แยกวิเคราะห์ เปลี่ยนคีย์ จากนั้นทำให้เป็นอนุกรมและตั้งค่ากลับเป็น Redis แนวทางนี้มีปัญหาสองสามประการ:

  1. การทำงานพร้อมกัน กระบวนการอื่นสามารถเปลี่ยน JSON นี้ระหว่างการดำเนินการรับและตั้งค่าของเรา ในกรณีนี้ การเปลี่ยนแปลงจะหายไป
  2. ประสิทธิภาพ หากคุณทำการเปลี่ยนแปลงเหล่านี้บ่อยเพียงพอและหากออบเจ็กต์ค่อนข้างใหญ่ สิ่งนี้อาจกลายเป็นปัญหาคอขวดของแอปของคุณ คุณสามารถชนะประสิทธิภาพได้โดยใช้ตรรกะนี้ใน Lua

มาเพิ่มสตริงทดสอบ JSON ให้กับ Redis ภายใต้คีย์ 140 :

set obj ‘{“a”:”foo”,”b”:”bar”}’

ตอนนี้มารันสคริปต์ของเรา:

EVAL ‘local obj = redis.call(“get”,KEYS[1]); local obj2 = string.gsub(obj,”(“ .. ARGV[1] .. “\”:)([^,}]+)”, “%1” .. ARGV[2]); return redis.call(“set”,KEYS[1],obj2);’ 1 obj b bar2

ตอนนี้เราจะมีวัตถุต่อไปนี้ภายใต้คีย์ 152 :

{“a”:”foo”,”b”:”bar2"}

คุณสามารถโหลดสคริปต์นี้ด้วย SCRIPT LOAD แทนได้ คำสั่ง:

SCRIPT LOAD ‘local obj = redis.call(“get”,KEYS[1]); local obj2 = string.gsub(obj,”(“ .. ARGV[1] .. “\”:)([^,}]+)”, “%1” .. ARGV[2]); return redis.call(“set”,KEYS[1],obj2);’

จากนั้นเรียกใช้ดังนี้:

EVALSHA <your_script_sha> 1 obj b bar2

หมายเหตุบางประการ:

  • 163 เป็นตัวดำเนินการต่อสตริงใน Lua
  • เราใช้รูปแบบ RegEx เพื่อจับคู่คีย์และแทนที่ค่าของมัน หากคุณไม่เข้าใจนิพจน์ทั่วไปนี้ คุณสามารถดูคำแนะนำล่าสุดของฉันได้
  • ความแตกต่างประการหนึ่งของรสชาติ Lua RegEx จากรสชาติอื่นๆ ส่วนใหญ่คือเราใช้ 176 เป็นทั้งเครื่องหมายอ้างอิงด้านหลังและอักขระหลีกสำหรับสัญลักษณ์พิเศษ RegEx
  • เรายังคงหนีจาก 180 ด้วย 190 และไม่ใช่ 202 เพราะเรายกเว้นตัวคั่นสตริง Lua ไม่ใช่สัญลักษณ์พิเศษ RegEx

ฉันควรใช้สคริปต์ Lua เสมอหรือไม่

ไม่ ฉันแนะนำให้ใช้เมื่อคุณสามารถพิสูจน์ได้ว่าผลลัพธ์นั้นมีประสิทธิภาพดีขึ้นเท่านั้น เรียกใช้การวัดประสิทธิภาพก่อนเสมอ

หากสิ่งที่คุณต้องการคืออะตอมมิกซิตี คุณควรตรวจสอบธุรกรรม Redis แทน

นอกจากนี้สคริปต์ของคุณไม่ควรยาวเกินไป โปรดจำไว้ว่าในขณะที่สคริปต์กำลังทำงาน สิ่งอื่นๆ กำลังรอให้สคริปต์เสร็จสิ้น หากสคริปต์ของคุณใช้เวลาค่อนข้างนาน ก็อาจทำให้เกิดปัญหาคอขวดแทนที่จะปรับปรุงประสิทธิภาพได้ สคริปต์หยุดหลังจากหมดเวลา (5 วินาทีโดยค่าเริ่มต้น)

การเขียนสคริปต์ Master Redis Lua:คู่มือปฏิบัติเพื่อเพิ่มประสิทธิภาพ สคริปต์ Redis ไม่ควรใช้เวลานานเกินไป

คำสุดท้าย

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ Lua โปรดตรวจสอบ lua.org

คุณสามารถตรวจสอบไลบรารี node.js ของฉันบน GitHub เพื่อดูตัวอย่างสคริปต์ Lua (ดู 214 โฟลเดอร์) คุณยังสามารถใช้ไลบรารีนี้ใน node.js เพื่อเปลี่ยนอ็อบเจ็กต์ JSON โดยไม่ต้องเขียนสคริปต์ Lua ด้วยตัวเอง

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

ขอขอบคุณที่อ่านบทความนี้ คำถามและความคิดเห็นได้รับการชื่นชมมาก คุณสามารถติดตามฉันได้เช่นกัน บนทวิตเตอร์ .

เรียนรู้การเขียนโค้ดฟรี หลักสูตรโอเพ่นซอร์สของ freeCodeCamp ช่วยให้ผู้คนมากกว่า 40,000 คนได้งานในตำแหน่งนักพัฒนา เริ่มต้น