ที่ Mail.ru Group เรามี Tarantool - นี่คือแอปพลิเคชันเซิร์ฟเวอร์ใน Lua ซึ่งเพิ่มเป็นสองเท่าของฐานข้อมูล (หรือกลับกัน?) มันรวดเร็วและยอดเยี่ยม แต่ความสามารถของเซิร์ฟเวอร์เดียวยังคงไม่จำกัด มาตราส่วนแนวตั้งไม่ใช่ยาครอบจักรวาล ดังนั้น Tarantool จึงมีเครื่องมือสำหรับมาตราส่วนแนวนอน - โมดูล vshard
ข่าวดี: เราได้รวบรวมภาพสำคัญบางส่วน (เช่น
จริงๆแล้วปัญหาคืออะไร?
เรามีทารันทูล่า เรามี vshard - คุณต้องการอะไรอีก?
ประการแรกมันเป็นเรื่องของความสะดวกสบาย การกำหนดค่า vshard ได้รับการกำหนดค่าผ่านตาราง Lua เพื่อให้ระบบแบบกระจายของกระบวนการ Tarantool หลายกระบวนการทำงานได้อย่างถูกต้อง การกำหนดค่าจะต้องเหมือนกันทุกที่ ไม่มีใครอยากทำเช่นนี้ด้วยตนเอง ดังนั้นจึงมีการใช้สคริปต์ Ansible และระบบการปรับใช้ทุกประเภท
คาร์ทริดจ์เองจัดการการกำหนดค่า vshard โดยจะทำสิ่งนี้ตาม การกำหนดค่าแบบกระจายของตัวเอง. โดยพื้นฐานแล้วมันเป็นไฟล์ YAML ธรรมดา โดยสำเนาของไฟล์จะถูกจัดเก็บไว้ในอินสแตนซ์ของ Tarantool แต่ละอินสแตนซ์ การทำให้ง่ายขึ้นคือเฟรมเวิร์กเองจะตรวจสอบการกำหนดค่าและรับรองว่าจะเหมือนกันทุกที่
ประการที่สองมันเป็นเรื่องของความสะดวกสบายอีกครั้ง การกำหนดค่า vshard ไม่เกี่ยวข้องกับการพัฒนาตรรกะทางธุรกิจ และเพียงรบกวนโปรแกรมเมอร์จากงานของเขาเท่านั้น เมื่อเราหารือเกี่ยวกับสถาปัตยกรรมของโครงการ เรามักจะพูดถึงแต่ละองค์ประกอบและการโต้ตอบของพวกเขา ยังเร็วเกินไปที่จะคิดเกี่ยวกับการเปิดตัวคลัสเตอร์ไปยังศูนย์ข้อมูล 3 แห่ง
เราแก้ไขปัญหาเหล่านี้ซ้ำแล้วซ้ำอีก และเมื่อถึงจุดหนึ่ง เราก็สามารถพัฒนาแนวทางที่ทำให้การทำงานกับแอปพลิเคชันง่ายขึ้นตลอดวงจรชีวิตทั้งหมด: การสร้าง การพัฒนา การทดสอบ CI/CD การบำรุงรักษา
คาร์ทริดจ์แนะนำแนวคิดเกี่ยวกับบทบาทสำหรับแต่ละกระบวนการของ Tarantool บทบาทเป็นแนวคิดที่ช่วยให้นักพัฒนามุ่งเน้นไปที่การเขียนโค้ด บทบาททั้งหมดที่มีอยู่ในโปรเจ็กต์สามารถรันบนอินสแตนซ์ Tarantool เดียวได้ และเพียงพอสำหรับการทดสอบ
คุณสมบัติที่สำคัญของตลับหมึก Tarantool:
- การประสานคลัสเตอร์อัตโนมัติ
- ขยายฟังก์ชันการทำงานของแอปพลิเคชันโดยใช้บทบาทใหม่
- เทมเพลตแอปพลิเคชันสำหรับการพัฒนาและการปรับใช้
- การแบ่งส่วนอัตโนมัติในตัว
- บูรณาการกับกรอบการทดสอบ Luatest
- การจัดการคลัสเตอร์โดยใช้ WebUI และ API
- เครื่องมือบรรจุภัณฑ์และการปรับใช้
สวัสดีชาวโลก!
ฉันแทบรอไม่ไหวที่จะแสดงเฟรมเวิร์ก ดังนั้นเราจะทิ้งเรื่องราวเกี่ยวกับสถาปัตยกรรมไว้ดูในภายหลังและเริ่มต้นด้วยสิ่งที่เรียบง่าย หากเราถือว่าติดตั้ง Tarantool แล้ว สิ่งเดียวที่เหลือก็คือต้องทำ
$ tarantoolctl rocks install cartridge-cli
$ export PATH=$PWD/.rocks/bin/:$PATH
คำสั่งทั้งสองนี้จะติดตั้งยูทิลิตีบรรทัดคำสั่งและอนุญาตให้คุณสร้างแอปพลิเคชันแรกจากเทมเพลต:
$ cartridge create --name myapp
และนี่คือสิ่งที่เราได้รับ:
myapp/
├── .git/
├── .gitignore
├── app/roles/custom.lua
├── deps.sh
├── init.lua
├── myapp-scm-1.rockspec
├── test
│ ├── helper
│ │ ├── integration.lua
│ │ └── unit.lua
│ ├── helper.lua
│ ├── integration/api_test.lua
│ └── unit/sample_test.lua
└── tmp/
นี่คือพื้นที่เก็บข้อมูล git พร้อม "Hello, World!" แอปพลิเคชัน. มาลองรันทันทีโดยติดตั้งการขึ้นต่อกันไว้ก่อนหน้านี้ (รวมถึงเฟรมเวิร์กด้วย):
$ tarantoolctl rocks make
$ ./init.lua --http-port 8080
ดังนั้นเราจึงมีหนึ่งโหนดที่ทำงานสำหรับแอปพลิเคชันที่แบ่งส่วนในอนาคต คนธรรมดาที่อยากรู้อยากเห็นสามารถเปิดเว็บอินเตอร์เฟสได้ทันที กำหนดค่าคลัสเตอร์ของโหนดเดียวด้วยเมาส์ และเพลิดเพลินกับผลลัพธ์ แต่ยังเร็วเกินไปที่จะชื่นชมยินดี จนถึงตอนนี้ แอปพลิเคชันไม่สามารถทำอะไรที่เป็นประโยชน์ได้ ดังนั้นฉันจะแจ้งให้คุณทราบเกี่ยวกับการปรับใช้ในภายหลัง แต่ตอนนี้ถึงเวลาเขียนโค้ดแล้ว
การพัฒนาโปรแกรมประยุกต์
ลองนึกภาพว่าเรากำลังออกแบบโครงการที่ต้องรับข้อมูล บันทึก และสร้างรายงานวันละครั้ง
เราเริ่มวาดไดอะแกรมและวางองค์ประกอบสามอย่างไว้: เกตเวย์ ที่เก็บข้อมูล และตัวกำหนดเวลา เรากำลังดำเนินการเกี่ยวกับสถาปัตยกรรมต่อไป เนื่องจากเราใช้ vshard เป็นที่เก็บข้อมูล เราจึงเพิ่ม vshard-router และ vshard-storage ให้กับโครงร่าง ทั้งเกตเวย์หรือตัวกำหนดเวลาจะไม่เข้าถึงที่เก็บข้อมูลโดยตรง นั่นคือสิ่งที่เราเตอร์มีไว้เพื่อ นั่นคือสิ่งที่มันถูกสร้างขึ้นมา
แผนภาพนี้ยังคงไม่ได้แสดงถึงสิ่งที่เราจะสร้างในโครงการอย่างแน่นอน เนื่องจากส่วนประกอบต่างๆ ดูเป็นนามธรรม เรายังคงต้องดูว่าสิ่งนี้จะถูกฉายลงบน Tarantool จริงได้อย่างไร - มาจัดกลุ่มส่วนประกอบของเราตามกระบวนการกัน
การเก็บ vshard-router และเกตเวย์ไว้บนอินสแตนซ์แยกกันแทบไม่มีประโยชน์เลย เหตุใดเราจึงต้องท่องเครือข่ายอีกครั้งหากนี่เป็นความรับผิดชอบของเราเตอร์อยู่แล้ว? จะต้องทำงานภายในกระบวนการเดียวกัน นั่นคือ ทั้งเกตเวย์และ vshard.router.cfg ได้รับการเตรียมใช้งานในกระบวนการเดียว และปล่อยให้ทั้งสองโต้ตอบกันในเครื่อง
ในขั้นตอนการออกแบบ มันสะดวกที่จะทำงานกับสามองค์ประกอบ แต่ฉันในฐานะนักพัฒนาในขณะที่เขียนโค้ด ไม่อยากคิดถึงการเปิดตัว Tarnatool สามอินสแตนซ์ ฉันต้องทำการทดสอบและตรวจสอบว่าฉันเขียนเกตเวย์อย่างถูกต้อง หรือบางทีฉันอาจต้องการสาธิตคุณลักษณะนี้ให้เพื่อนร่วมงานเห็น เหตุใดฉันจึงต้องเจอกับความยุ่งยากในการปรับใช้สำเนาสามชุด? นี่คือที่มาของแนวคิดเรื่องบทบาท บทบาทคือโมดูล luash ปกติซึ่งมีการจัดการวงจรชีวิตโดยคาร์ทริดจ์ ในตัวอย่างนี้มีสี่รายการ ได้แก่ เกตเวย์ เราเตอร์ ที่เก็บข้อมูล ตัวกำหนดเวลา อาจมีเพิ่มเติมในโครงการอื่น บทบาททั้งหมดสามารถดำเนินการได้ในกระบวนการเดียว แค่นี้ก็เพียงพอแล้ว
และเมื่อพูดถึงการปรับใช้งานในการแสดงละครหรือการใช้งานจริง เราจะมอบหมายชุดบทบาทของตนเองให้กับแต่ละกระบวนการของ Tarantool โดยขึ้นอยู่กับความสามารถของฮาร์ดแวร์:
การจัดการโทโพโลยี
ข้อมูลเกี่ยวกับตำแหน่งที่กำลังทำงานอยู่จะต้องถูกเก็บไว้ที่ใดที่หนึ่ง และ "ที่ไหนสักแห่ง" นี้คือการกำหนดค่าแบบกระจายซึ่งฉันได้กล่าวไปแล้วข้างต้น สิ่งที่สำคัญที่สุดคือโทโพโลยีคลัสเตอร์ นี่คือกลุ่มการจำลอง 3 กลุ่มจาก 5 กระบวนการ Tarantool:
เราไม่ต้องการสูญเสียข้อมูล ดังนั้นเราจึงปฏิบัติต่อข้อมูลเกี่ยวกับกระบวนการที่ดำเนินอยู่ด้วยความระมัดระวัง คาร์ทริดจ์ติดตามการกำหนดค่าโดยใช้การคอมมิตแบบสองเฟส เมื่อเราต้องการอัปเดตการกำหนดค่า ก่อนอื่นจะตรวจสอบว่าอินสแตนซ์ทั้งหมดพร้อมใช้งานและพร้อมที่จะยอมรับการกำหนดค่าใหม่ หลังจากนี้ ระยะที่สองจะใช้การกำหนดค่า ดังนั้น แม้ว่าสำเนาหนึ่งชุดจะไม่สามารถใช้งานได้ชั่วคราว แต่ก็ไม่มีอะไรเลวร้ายเกิดขึ้น การกำหนดค่าจะไม่ถูกนำไปใช้และคุณจะเห็นข้อผิดพลาดล่วงหน้า
นอกจากนี้ในส่วนโทโพโลยี ยังมีการระบุพารามิเตอร์ที่สำคัญในฐานะผู้นำของกลุ่มการจำลองแต่ละกลุ่มด้วย โดยปกติแล้วนี่คือสำเนาที่กำลังถูกบันทึกไว้ ส่วนที่เหลือมักเป็นแบบอ่านอย่างเดียว แม้ว่าอาจมีข้อยกเว้นก็ตาม บางครั้งนักพัฒนาที่กล้าหาญก็ไม่กลัวความขัดแย้งและสามารถเขียนข้อมูลไปยังแบบจำลองหลาย ๆ แบบพร้อมกันได้ แต่มีการดำเนินการบางอย่างที่ไม่ควรดำเนินการสองครั้งไม่ว่าจะอย่างไรก็ตาม สำหรับสิ่งนี้มีสัญญาณของผู้นำ
ชีวิตของบทบาท
เพื่อให้มีบทบาทเชิงนามธรรมในสถาปัตยกรรมดังกล่าว กรอบงานจะต้องจัดการบทบาทเหล่านั้นด้วยวิธีใดวิธีหนึ่ง โดยปกติแล้ว การควบคุมจะเกิดขึ้นโดยไม่ต้องรีสตาร์ทกระบวนการ Tarantool มีการโทรกลับ 4 รายการเพื่อจัดการบทบาท คาร์ทริดจ์จะเรียกสิ่งเหล่านี้โดยขึ้นอยู่กับสิ่งที่เขียนไว้ในการกำหนดค่าแบบกระจาย ดังนั้นจึงใช้การกำหนดค่ากับบทบาทเฉพาะ
function init()
function validate_config()
function apply_config()
function stop()
แต่ละบทบาทมีหน้าที่ init
. มันถูกเรียกหนึ่งครั้งเมื่อเปิดใช้งานบทบาทหรือเมื่อรีสตาร์ท Tarantool สะดวกเช่นในการเริ่มต้น box.space.create หรือตัวกำหนดเวลาสามารถเรียกใช้ไฟเบอร์พื้นหลังบางส่วนที่จะทำงานในช่วงเวลาที่กำหนด
ฟังก์ชั่นหนึ่ง init
อาจไม่เพียงพอ คาร์ทริดจ์อนุญาตให้บทบาทใช้ประโยชน์จากการกำหนดค่าแบบกระจายที่ใช้ในการจัดเก็บโทโพโลยี เราสามารถประกาศส่วนใหม่ในการกำหนดค่าเดียวกันและจัดเก็บส่วนย่อยของการกำหนดค่าทางธุรกิจไว้ได้ ในตัวอย่างของฉัน นี่อาจเป็นสคีมาข้อมูลหรือการตั้งค่ากำหนดการสำหรับบทบาทผู้จัดกำหนดการ
การโทรแบบคลัสเตอร์ validate_config
и apply_config
ทุกครั้งที่มีการเปลี่ยนแปลงการกำหนดค่าแบบกระจาย เมื่อใช้การกำหนดค่าโดยการคอมมิตแบบสองเฟส คลัสเตอร์จะตรวจสอบว่าแต่ละบทบาทพร้อมที่จะยอมรับการกำหนดค่าใหม่นี้ และหากจำเป็น จะรายงานข้อผิดพลาดให้กับผู้ใช้ เมื่อทุกคนตกลงกันว่าการกำหนดค่าเป็นเรื่องปกติแล้ว apply_config
.
บทบาทก็มีวิธีการเช่นกัน stop
ซึ่งจำเป็นในการล้างเอาต์พุตของบทบาท หากเราบอกว่าไม่จำเป็นต้องใช้ตัวกำหนดเวลาบนเซิร์ฟเวอร์นี้อีกต่อไป ก็สามารถหยุดไฟเบอร์ที่เริ่มต้นด้วยได้ init
.
บทบาทสามารถโต้ตอบซึ่งกันและกันได้ เราคุ้นเคยกับการเขียนการเรียกใช้ฟังก์ชันใน Lua แต่อาจเกิดขึ้นได้ว่ากระบวนการที่กำหนดไม่มีบทบาทที่เราต้องการ เพื่ออำนวยความสะดวกในการโทรผ่านเครือข่าย เราใช้โมดูลเสริม rpc (การเรียกขั้นตอนระยะไกล) ซึ่งสร้างขึ้นบนพื้นฐานของ netbox มาตรฐานที่สร้างไว้ใน Tarantool สิ่งนี้อาจมีประโยชน์ ตัวอย่างเช่น เกตเวย์ของคุณต้องการขอให้ผู้จัดกำหนดการทำงานทันทีโดยตรง แทนที่จะรอสักวัน
จุดสำคัญอีกประการหนึ่งคือการประกันความทนทานต่อข้อผิดพลาด คาร์ทริดจ์ใช้โปรโตคอล SWIM เพื่อตรวจสอบสุขภาพ
ตามโปรโตคอลนี้ คาร์ทริดจ์จะจัดการประมวลผลความล้มเหลวโดยอัตโนมัติ แต่ละกระบวนการจะตรวจสอบสภาพแวดล้อม และหากผู้นำหยุดตอบสนองกะทันหัน แบบจำลองก็สามารถเข้ามามีบทบาทแทนได้ และตลับหมึกจะกำหนดค่าบทบาทที่ทำงานอยู่ตามลำดับ
คุณต้องระมัดระวังที่นี่ เนื่องจากการสลับไปมาบ่อยครั้งอาจทำให้เกิดข้อขัดแย้งของข้อมูลในระหว่างการจำลองแบบ แน่นอนว่าคุณไม่ควรเปิดใช้งานการเฟลโอเวอร์อัตโนมัติโดยการสุ่ม เราต้องเข้าใจอย่างชัดเจนว่าเกิดอะไรขึ้น และตรวจสอบให้แน่ใจว่าการจำลองจะไม่พังหลังจากที่ผู้นำได้รับการฟื้นฟูและมอบมงกุฎคืนให้เขาแล้ว
จากทั้งหมดนี้ คุณอาจรู้สึกว่าบทบาทนั้นคล้ายคลึงกับไมโครเซอร์วิส ในแง่หนึ่ง มันเป็นเพียงโมดูลภายในกระบวนการของ Tarantool เท่านั้น แต่ก็มีความแตกต่างพื้นฐานหลายประการเช่นกัน ขั้นแรก บทบาทของโปรเจ็กต์ทั้งหมดต้องอยู่ในฐานโค้ดเดียวกัน และกระบวนการ Tarantool ทั้งหมดควรเริ่มต้นจากฐานโค้ดเดียวกัน เพื่อไม่ให้เกิดความประหลาดใจเหมือนเมื่อเราพยายามเริ่มต้นตัวกำหนดตารางเวลา แต่ไม่มีอยู่จริง นอกจากนี้ คุณไม่ควรปล่อยให้เกิดความแตกต่างในเวอร์ชันของโค้ด เนื่องจากลักษณะการทำงานของระบบในสถานการณ์ดังกล่าวเป็นเรื่องยากมากที่จะคาดเดาและแก้ไขจุดบกพร่อง
ต่างจาก Docker ตรงที่เราไม่สามารถรับหน้าที่เป็น "อิมเมจ" นำไปที่เครื่องอื่นแล้วรันที่นั่นได้ บทบาทของเราไม่ได้โดดเดี่ยวเหมือนคอนเทนเนอร์นักเทียบท่า นอกจากนี้ เราไม่สามารถเรียกใช้สองบทบาทที่เหมือนกันบนอินสแตนซ์เดียวได้ บทบาทนั้นมีอยู่หรือไม่มีอยู่ ในแง่หนึ่ง มันเป็นซิงเกิลตัน และประการที่สาม บทบาทจะต้องเหมือนกันภายในกลุ่มการจำลองทั้งหมด เพราะไม่เช่นนั้นจะไร้สาระ - ข้อมูลเหมือนกัน แต่การกำหนดค่าแตกต่างกัน
เครื่องมือการปรับใช้
ฉันสัญญาว่าจะแสดงให้เห็นว่าตลับหมึกช่วยปรับใช้แอปพลิเคชันได้อย่างไร เพื่อให้ชีวิตของผู้อื่นง่ายขึ้น เฟรมเวิร์กจึงรวมแพ็คเกจ RPM:
$ cartridge pack rpm myapp -- упакует для нас ./myapp-0.1.0-1.rpm
$ sudo yum install ./myapp-0.1.0-1.rpm
แพ็คเกจที่ติดตั้งมีเกือบทุกอย่างที่คุณต้องการ: ทั้งแอปพลิเคชันและการอ้างอิงที่ติดตั้ง Tarantool จะมาถึงเซิร์ฟเวอร์โดยขึ้นอยู่กับแพ็คเกจ RPM และบริการของเราพร้อมที่จะเปิดตัว ทำได้ผ่าน systemd แต่ก่อนอื่นคุณต้องเขียนการกำหนดค่าเล็กน้อยก่อน อย่างน้อยที่สุด ให้ระบุ URI ของแต่ละกระบวนการ ตัวอย่างเช่นสามก็เพียงพอแล้ว
$ sudo tee /etc/tarantool/conf.d/demo.yml <<CONFIG
myapp.router: {"advertise_uri": "localhost:3301", "http_port": 8080}
myapp.storage_A: {"advertise_uri": "localhost:3302", "http_enabled": False}
myapp.storage_B: {"advertise_uri": "localhost:3303", "http_enabled": False}
CONFIG
มีความแตกต่างที่น่าสนใจที่นี่ แทนที่จะระบุเฉพาะพอร์ตโปรโตคอลไบนารี เราจะระบุที่อยู่สาธารณะทั้งหมดของกระบวนการ รวมถึงชื่อโฮสต์ด้วย นี่เป็นสิ่งจำเป็นเพื่อให้โหนดคลัสเตอร์รู้วิธีการเชื่อมต่อระหว่างกัน เป็นความคิดที่ดีที่จะใช้ 0.0.0.0 เป็นที่อยู่ ads_uri ซึ่งควรเป็นที่อยู่ IP ภายนอก ไม่ใช่การผูกซ็อกเก็ต หากไม่มีมันก็จะไม่มีอะไรทำงาน ดังนั้นคาร์ทริดจ์จะไม่ยอมให้คุณเปิดโหนดที่มีโฆษณาที่ไม่ถูกต้อง
เมื่อการกำหนดค่าพร้อมแล้ว คุณสามารถเริ่มกระบวนการได้ เนื่องจากหน่วย systemd ปกติไม่อนุญาตให้เริ่มกระบวนการมากกว่าหนึ่งกระบวนการ แอปพลิเคชันบนตลับหมึกจึงได้รับการติดตั้งโดยสิ่งที่เรียกว่า หน่วยอินสแตนซ์ที่ทำงานดังนี้:
$ sudo systemctl start myapp@router
$ sudo systemctl start myapp@storage_A
$ sudo systemctl start myapp@storage_B
ในการกำหนดค่าเราระบุพอร์ต HTTP ที่ตลับหมึกให้บริการเว็บอินเตอร์เฟส - 8080 ไปดูกันดีกว่า:
เราเห็นว่าแม้ว่ากระบวนการกำลังทำงานอยู่ แต่ก็ยังไม่ได้รับการกำหนดค่า คาร์ทริดจ์ยังไม่รู้ว่าใครควรทำซ้ำกับใครและไม่สามารถตัดสินใจได้ด้วยตัวเองดังนั้นจึงรอการดำเนินการของเรา แต่เราไม่มีทางเลือกมากนัก อายุการใช้งานของคลัสเตอร์ใหม่เริ่มต้นด้วยการกำหนดค่าของโหนดแรก จากนั้นเราจะเพิ่มคนอื่นๆ ลงในคลัสเตอร์ มอบหมายบทบาทให้พวกเขา และ ณ จุดนี้ถือว่าการปรับใช้งานเสร็จสมบูรณ์แล้ว
มาดื่มเครื่องดื่มแก้วโปรดของคุณสักแก้วแล้วผ่อนคลายหลังจากทำงานหนักมาทั้งสัปดาห์ สามารถใช้แอปพลิเคชันได้
ผลของการ
ผลลัพธ์คืออะไร? ลองใช้ ใช้งาน แสดงความคิดเห็น สร้างตั๋วบน Github
การอ้างอิง
[1]
ที่มา: will.com