วิธีสร้างแอปพลิเคชั่น Golang แบบเสียบได้และรับประโยชน์จาก AWS แลมบ์ดาเลเยอร์

Golang - ทำไมความสนใจของคุณถึงคุ้มค่า?

Golang เป็นภาษาโปรแกรมโอเพนซอร์ซที่ออกแบบและดำเนินการโดย Google มีการใช้กันอย่างแพร่หลายในแอปพลิเคชันที่ทันสมัยโดยเฉพาะในระบบคลาวด์ มันเป็นคุณสมบัติที่โดดเด่นที่สุดคือ:

  • Golang ถูกพิมพ์แบบสแตติก - ให้ความยืดหยุ่นน้อยลง แต่ปกป้องคุณจากการทำผิดพลาด
  • มันไม่ได้เป็นเชิงวัตถุ อย่างไรก็ตามคุณสามารถสร้างโครงสร้างและอินเทอร์เฟซและให้หลักการ 3 ใน 4 ของ OOP: ข้อมูลนามธรรมการห่อหุ้มและ polymorphism มรดกเป็นสิ่งเดียวที่ขาดหายไป
  • Goroutines! - การใช้งานไลท์ติ้งที่ยิ่งใหญ่ที่สุดที่ฉันเคยใช้ จะช่วยให้คุณสร้างหัวข้อใหม่ในวิธีที่ง่ายสุด ๆ โดยใช้ตัวดำเนินการ Go และสื่อสารระหว่าง goroutines ที่ต่างกันโดยใช้ช่อง
  • มันรวบรวมไปยังไบนารีเดียวที่มีการอ้างอิงทั้งหมด - ไม่มีความขัดแย้งของแพ็คเกจอีกต่อไป!

ส่วนตัวฉันคิดว่า Golang เป็นภาษาที่ยิ่งใหญ่ที่สุดที่ฉันใช้ในชีวิตประจำวัน อย่างไรก็ตามบทความนี้จะไม่เกี่ยวกับการสร้างฟังก์ชั่นแรกของคุณหรือการพิมพ์ "Hello World" ฉันจะแสดงให้คุณเห็นสิ่งที่สูงขึ้นอีกเล็กน้อย หากคุณเป็นมือใหม่และต้องการเรียนรู้เพิ่มเติมเกี่ยวกับโกลังกรุณาเยี่ยมชมหน้าหลัก

AWS Lambda & Golang

AWS Lambda เป็นหนึ่งในบริการคำนวณแบบไม่มีเซิร์ฟเวอร์ที่ได้รับความนิยมมากที่สุดในระบบคลาวด์สาธารณะซึ่งเปิดตัวในเดือนพฤศจิกายน 2014 โดย Amazon Web Services ช่วยให้คุณสามารถเรียกใช้รหัสของคุณในการตอบสนองต่อเหตุการณ์เช่น DynamoDB, SNS หรือ HTTP ทริกเกอร์โดยไม่ต้องจัดเตรียมหรือจัดการเซิร์ฟเวอร์! คุณรู้หรือไม่ว่าอะไรยอดเยี่ยมจริง ๆ ? ตั้งแต่มกราคม 2018 รองรับ Golang runtime การทำงานกับ AWS แลมบ์ดานั้นง่ายมากเพียงอัปโหลดแพ็คเกจซิปพร้อมรหัสของคุณและการอ้างอิงทั้งหมด (ไบนารีเดียวเมื่อใช้ Golang)

กรอไปข้างหน้าอย่างรวดเร็ว 4 ปีต่อมาในปี 2018 อีกครั้ง: คิดค้น AWS เปิดตัวแลมบ์ดาเลเยอร์ที่ให้คุณจัดเก็บและจัดการข้อมูลที่ใช้ร่วมกันในฟังก์ชั่นต่าง ๆ ในบัญชี AWS เดียวหรือหลายบัญชี! ตัวอย่างเช่นในขณะที่ใช้ Python คุณสามารถใส่การอ้างอิงทั้งหมดในเลเยอร์เพิ่มเติมซึ่งสามารถใช้งานได้ในภายหลังโดย Lambdas อื่น ไม่จำเป็นต้องใส่การอ้างอิงที่แตกต่างกันในแต่ละแพ็คเกจที่ซิปอีกต่อไป! ในสถานการณ์โลก Golang นั้นแตกต่างกันเนื่องจาก AWS Lambda ต้องการให้คุณอัพโหลดไบนารีที่คอมไพล์แล้ว เราจะได้ประโยชน์จากเลเยอร์ AWS Lambda อย่างไร คำตอบนั้นง่าย - สร้างแอพพลิเคชั่นแบบแยกส่วนโดยใช้ Golang Plugins!

Golang Plugins - วิธีสร้างแอพพลิเคชั่นแบบแยกส่วน

Golang Plugins เป็นคุณสมบัติที่วางจำหน่ายใน Go1.8 ที่ให้คุณโหลดไลบรารีที่แชร์ (ไฟล์. so) แบบไดนามิก มันให้โอกาสคุณในการส่งออกโค้ดบางส่วนไปยังไลบรารี่แยกต่างหากหรือใช้ปลั๊กอินที่เตรียมและรวบรวมโดยบุคคลอื่น อย่างไรก็ตามสัญญามีข้อ จำกัด บางประการดังนี้:

  • ปลั๊กอินของคุณจะต้องเป็นโมดูลหลักเดียว
  • คุณสามารถโหลดเฉพาะฟังก์ชั่นและตัวแปรที่ส่งออกเป็นสัญลักษณ์เอลฟ์
  • เนื่องจากการพิมพ์แบบสแตติกคุณต้องแปลงสัญลักษณ์ที่โหลดทุกชนิดเป็นชนิดที่ถูกต้อง ในสถานการณ์ที่เลวร้ายที่สุดคุณต้องกำหนดอินเทอร์เฟซที่ถูกต้องในรหัสของคุณ
  • ใช้งานได้กับ Linux และ MacOS เท่านั้น โดยส่วนตัวฉันไม่คิดว่านี่เป็นข้อเสีย :)

สร้างและทดสอบปลั๊กอินแรกของคุณ

ตอนนี้ให้สร้างปลั๊กอินแรกของเรา ตัวอย่างเช่นเราจะสร้างโมดูลอย่างง่ายสำหรับการเข้ารหัสสตริง กลับไปสู่พื้นฐานและใช้อัลกอริธึมการเข้ารหัสง่าย ๆ 2 แบบคือ Ceasar และ Verman

  • Caesar cipher เป็นอัลกอริธึมที่ Julius C เผยแพร่ใช้เป็นครั้งแรก มันเลื่อนตัวอักษรทุกตัวในข้อความตามจำนวนตำแหน่งที่แน่นอน ตัวอย่างเช่นหากคุณต้องการเข้ารหัสคำ golang ด้วยรหัส 4 คุณจะได้รับ ktpek การถอดรหัสจะทำงานในลักษณะเดียวกัน คุณเพียงแค่ต้องเปลี่ยนตัวอักษรไปในทิศทางตรงกันข้าม
  • เลขศูนย์ของ Verman นั้นคล้ายกับ Ceaser โดยขึ้นอยู่กับแนวคิดการเปลี่ยนแปลงที่เหมือนกันความแตกต่างคือคุณเปลี่ยนจดหมายทุกฉบับตามตำแหน่งที่แตกต่างกัน ในการถอดรหัสข้อความคุณต้องมีคีย์ที่มีตำแหน่งที่ใช้ในการเข้ารหัสข้อความ ตัวอย่างเช่นหากคุณต้องการเข้ารหัสคำ golang ด้วยปุ่ม [-1, 4, 7, 20, 4, -2] คุณจะได้รับอนาคต

การนำตัวอย่างนี้ไปใช้อย่างสมบูรณ์มีให้ที่นี่

การใช้งานปลั๊กอิน

ตัวอย่างต่อไปนี้มีการใช้งานของสองอัลกอริทึมที่กล่าวถึงข้างต้น สำหรับแต่ละคนเราใช้วิธีการเข้ารหัสและถอดรหัสข้อความของเรา 2 วิธี:

อย่างที่คุณเห็นเราส่งออกสัญลักษณ์ที่แตกต่างกัน 3 ตัวที่นี่ (Golang ส่งออกเฉพาะตัวบ่งชี้เหล่านี้ที่ขึ้นต้นด้วยตัวอักษรตัวใหญ่):

  • EncryptCeasar - สตริง func (int, string) ที่เข้ารหัสข้อความโดยใช้อัลกอริทึม Ceasar
  • DecryptCeaser - สตริง func (int, string) ที่ถอดรหัสข้อความโดยใช้อัลกอริทึม Caeser
  • VermanCipher - ตัวแปรประเภท vermanCipher ใช้ 2 วิธี: เข้ารหัส: สตริง func (สตริง) และถอดรหัส: func () (* สตริงข้อผิดพลาด)

เพื่อรวบรวมปลั๊กอินนี้คุณต้องเรียกใช้คำสั่งต่อไปนี้:

ไปสร้าง -buildmode = plugin -o plugin / cipher.so plugin / cipher.go

สำหรับตอนนี้ไม่มีอะไรพิเศษ - มีการสร้างฟังก์ชั่นง่ายๆและโมดูลถูกคอมไพล์เป็นปลั๊กอินโดยการเพิ่มอาร์กิวเมนต์ -buildmode = plugin

โหลดและทดสอบปลั๊กอิน

ความสนุกเริ่มต้นขึ้นเมื่อเราต้องการใช้ปลั๊กอินที่คอมไพล์ในแอพของเรา มาสร้างตัวอย่างง่ายๆ:

ก่อนอื่นคุณต้องนำเข้าแพ็คเกจปลั๊กอิน golang มันมีเพียงสองฟังก์ชั่น - อันแรกคือสำหรับการโหลดห้องสมุดสาธารณะและที่สองคือการหาสัญลักษณ์ส่งออก ในการโหลดไลบรารี่ของคุณคุณจะต้องใช้ฟังก์ชั่นเปิดซึ่งต้องระบุเส้นทางไปยังปลั๊กอินที่แชร์ของคุณและส่งกลับตัวแปรประเภทปลั๊กอิน หากการโหลดห้องสมุดเป็นไปไม่ได้ (เช่นเส้นทางที่ไม่ถูกต้องหรือไฟล์เสียหาย) ฟังก์ชั่นนี้จะส่งกลับข้อผิดพลาดที่ต้องจัดการ

ขั้นตอนต่อไปคือการโหลดทุกสัญลักษณ์ที่ส่งออกโดยใช้วิธีการค้นหา ความไม่สะดวกเล็กน้อยคือคุณต้องโหลดทุกฟังก์ชั่นที่ส่งออกแยกต่างหาก อย่างไรก็ตามคุณสามารถรวมหลายฟังก์ชั่นเข้าด้วยกันในลักษณะเดียวกับที่ทำกับสัญลักษณ์ VermanCipher เมื่อคุณโหลดสัญลักษณ์ทั้งหมดที่คุณต้องการใช้คุณจะต้องโยนมันลงในประเภทที่ถูกต้อง Golang เป็นภาษาที่พิมพ์แบบคงที่ดังนั้นจึงไม่มีวิธีอื่นในการใช้สัญลักษณ์เหล่านี้โดยไม่ต้องร่าย โปรดจำไว้ว่าเมื่อคุณส่งออกตัวแปรที่ใช้สองสามวิธีคุณจำเป็นต้องแปลงเป็นประเภทอินเตอร์เฟสที่ถูกต้อง (ฉันต้องกำหนด interfaceEngine เข้ารหัสเพื่อจัดการสิ่งนี้) \ newline \ newline

ในการรวบรวมและเรียกใช้แอปให้ใช้คำสั่งต่อไปนี้:

ไปสร้าง app.go
./app

ในผลลัพธ์คุณควรเห็นข้อความที่เข้ารหัสและถอดรหัสเป็นหลักฐานว่าอัลกอริทึมทำงานอย่างถูกต้อง

ใช้ปลั๊กอินในแลมบ์ดา AWS

ในการใช้ปลั๊กอินของเราใน AWS Lambda เราจำเป็นต้องทำการแก้ไขเล็กน้อยในแอปพลิเคชันของเรา:

  • AWS แลมบ์ดาติดเลเยอร์ไปยังไดเรกทอรี / opt ในแลมบ์ดาคอนเทนเนอร์ดังนั้นเราต้องโหลดปลั๊กอินของเราจากไดเรกทอรีนี้
  • เราจำเป็นต้องสร้างฟังก์ชั่นจัดการที่จะใช้โดยเครื่องยนต์แลมบ์ดาเพื่อจัดการกับกิจกรรมทดสอบของเรา

ตัวอย่างต่อไปนี้มีแอปพลิเคชันของเราที่ปรับให้ใช้โดย Lambda:

ดังที่คุณเห็นการใช้งานนั้นคล้ายกับรุ่นก่อนหน้ามาก เราได้เปลี่ยนเฉพาะไดเรกทอรีที่เราโหลดปลั๊กอินของเราและเพิ่มการตอบสนองการทำงานแทนการพิมพ์ค่า หากคุณต้องการเรียนรู้เพิ่มเติมเกี่ยวกับการเขียน Lambdas ใน golang โปรดตรวจสอบเอกสาร AWS

การปรับใช้ AWS Lambda

มีสองวิธีในการปรับใช้ฟังก์ชันและเลเยอร์ AWS Lambda คุณสามารถสร้างและอัพโหลดแพ็คเกจซิปด้วยตนเองหรือใช้เฟรมเวิร์กขั้นสูงซึ่งทำให้ง่ายขึ้นและเร็วขึ้น สำหรับโครงการส่วนใหญ่ของฉันฉันใช้ Serverless framework ดังนั้นฉันได้เตรียมไฟล์การกำหนดค่า serverless.yml อย่างง่ายแล้วโดยใช้เครื่องมือนี้:

บริการ: cipherService
frameworkVersion: "> = 1.28.0 <2.0.0"
ผู้ให้บริการ:
  ชื่อ: aws
  รันไทม์: go1.x
ชั้น:
  cipherLayer:
    path: bin / plugin
    compatibleRuntimes:
      - go1.x
ฟังก์ชั่น:
  เครื่องยนต์:
    ตัวจัดการ: bin / cipherEngine
    แพคเกจ:
      ไม่รวม:
        - ./**
      รวมถึง:
        - ./bin/cipherEngine
    ชั้น:
      - {Ref: CipherLayerLambdaLayer}

ในส่วนเลเยอร์เรากำหนดเลเยอร์เดี่ยวพร้อมเส้นทางไปยังปลั๊กอินที่สร้างขึ้นแล้ว - มันจะถูกนำไปใช้งานร่วมกับฟังก์ชั่นแลมบ์ดา คุณสามารถกำหนดเลเยอร์ที่แตกต่างกันได้ถึง 5 ชั้นซึ่งคำสั่งนั้นสำคัญมาก พวกมันจะถูกเมาท์ไปที่ไดเร็กตอรี่ / opt เดียวกันดังนั้นเลเยอร์ที่มีจำนวนที่สูงกว่าจะสามารถแทนที่ไฟล์ได้จากเลเยอร์ที่เมาท์ก่อนหน้านี้ สำหรับทุกเลเยอร์คุณต้องระบุอย่างน้อย 2 พารามิเตอร์: พา ธ ไปยังไดเร็กทอรีที่มีเลเยอร์ซอร์ส (พา ธ ไปยังปลั๊กอินไบนารีในกรณีของคุณ) และรายการของรันไทม์ที่ใช้งานร่วมกันได้

ส่วนฟังก์ชั่นถัดไปเป็นสถานที่ที่คุณกำหนดรายการฟังก์ชั่นที่จะนำไปใช้งาน สำหรับทุกฟังก์ชั่นคุณต้องระบุเส้นทางไปยังแอปพลิเคชันที่รวบรวมไว้อย่างน้อย นอกจากนี้เราต้องกำหนดพารามิเตอร์ layer ด้วยการอ้างอิงถึง layer ที่กำหนดไว้ด้านบน สิ่งนี้จะแนบเลเยอร์เข้ากับฟังก์ชัน Lambda ของเราโดยอัตโนมัติระหว่างการปรับใช้ สิ่งที่ตลกคือคุณต้องแปลงชื่อเลเยอร์แลมบ์ดาของคุณให้เป็น TitleCased และเพิ่มคำต่อท้าย LambdaLayer หากคุณต้องการอ้างถึงทรัพยากรนั้น ดูเหมือนว่าทีม Serverless จะใช้วิธีนี้เพื่อแก้ไขข้อขัดแย้งโดยอ้างอิงกับทรัพยากรประเภทต่างๆ

เมื่อไฟล์การกำหนดค่า serverless.yml ของเราพร้อมสิ่งสุดท้ายที่ต้องทำคือการรวบรวมแอพของเราปลั๊กอินและปรับใช้ เราสามารถใช้ Makefile อย่างง่ายสำหรับสิ่งต่อไปนี้:

.PHONY: สร้าง buildPlugin การปรับใช้ที่สะอาด
สร้าง:
 ให้แน่ใจว่า -v
 env GOOS = linux go build -ldflags = "- s -w" -o bin / cipherEngine cipherEngine / main.go
buildPlugin:
 env GOOS = linux go build -ldflags = "- s -w" -buildmode = plugin -o bin / plugin / cipher.so ../plugin/cipher.go
สะอาด
 rm -rf ./bin ./vendor Gopkg.lock
ปรับใช้: clean buildPlugin build
 sls ปรับใช้ --verbose

คุณสามารถสร้างและปรับใช้ฟังก์ชั่นของคุณโดยใช้คำสั่งต่อไปนี้

ทำให้การปรับใช้

ทดสอบ AWS แลมบ์ดา

ดังที่ฉันได้กล่าวถึง AWS แลมบ์ดาเรียกใช้รหัสในการตอบสนองต่อเหตุการณ์ อย่างไรก็ตามเราไม่ได้กำหนดค่าทริกเกอร์เหตุการณ์ใด ๆ ดังนั้นจะไม่ถูกเรียกใช้หากไม่มีความช่วยเหลือ เราต้องทำด้วยตนเองโดยใช้กรอบ Serverless หรือเครื่องมือ awscli:

sls เรียกใช้ -f function_name
aws lambda เรียกใช้ - function-name function_name output_file

ในการตอบกลับคุณจะเห็นผลลัพธ์เหมือนเดิมซึ่งพิสูจน์ว่าฟังก์ชั่นแลมบ์ดาของเราทำงานได้อย่างถูกต้องและโหลดปลั๊กอินจากเลเยอร์เพิ่มเติม ตอนนี้คุณสามารถสร้างฟังก์ชั่นอื่น ๆ ที่จะใช้เลเยอร์เดียวกันหรือแม้กระทั่งแบ่งปันกับบัญชี AWS อื่น ๆ

สรุป

มันสนุกมากที่ได้ใช้โมดูล Golang และทดสอบวิธีรวมเข้ากับเลเยอร์ AWS Lambda ที่เพิ่งเปิดตัวใหม่ ห้องสมุดปลั๊กอินนั้นยอดเยี่ยมมาก แต่เนื่องจากข้อ จำกัด และข้อกำหนดของ Golang จึงสามารถใช้ได้เฉพาะในบางสถานการณ์พิเศษ ฉันคิดว่าสำหรับนักพัฒนาซอฟต์แวร์ส่วนใหญ่ที่ทำงานในโครงการมาตรฐานจะไม่จำเป็นต้องใช้หรือเป็นไปได้ที่จะใช้ปลั๊กอิน มีเพียงสองเหตุผลที่มาถึงใจของฉัน:

  • การนำอัลกอริธึมที่ซับซ้อนมาใช้ซึ่งแอปพลิเคชันอื่นสามารถใช้งานได้ อัลกอริธึมการเข้ารหัสวิดีโอหรือการเข้ารหัส
  • แบ่งปันอัลกอริทึมของคุณกับผู้อื่นโดยไม่ต้องเผยแพร่โค้ด