สถาปัตยกรรม Microservice เป็นแนวทางที่ได้รับความนิยมอย่างมากในการออกแบบและใช้งานเว็บแอปพลิเคชันที่ปรับขนาดได้สูง การสื่อสารภายในแอปพลิเคชันเสาหินระหว่างส่วนประกอบมักจะขึ้นอยู่กับการเรียกใช้วิธีการหรือฟังก์ชันภายในกระบวนการเดียวกัน ในทางกลับกันแอปพลิเคชันที่ใช้ไมโครเซอร์วิสเป็นระบบกระจายที่ทำงานบนเครื่องหลายเครื่อง
การสื่อสารระหว่างไมโครเซอร์วิสเหล่านี้มีความสำคัญเพื่อให้ระบบมีเสถียรภาพและปรับขนาดได้ มีหลายวิธีในการดำเนินการนี้ การสื่อสารด้วยข้อความเป็นวิธีหนึ่งในการดำเนินการนี้อย่างน่าเชื่อถือ
ตัวอย่างโหนด js ส่วนที่เหลือไคลเอ็นต์
เมื่อใช้การรับส่งข้อความส่วนประกอบจะโต้ตอบกันโดยการแลกเปลี่ยนข้อความแบบอะซิงโครนัส มีการแลกเปลี่ยนข้อความผ่านช่องทาง
เมื่อบริการ A ต้องการสื่อสารกับบริการ B แทนที่จะส่งโดยตรง A จะส่งไปยังช่องเฉพาะ เมื่อ Service B ต้องการอ่านข้อความจะรับข้อความจากช่องข้อความเฉพาะ
ในบทช่วยสอน Spring Integration นี้คุณจะได้เรียนรู้วิธีใช้การส่งข้อความในแอปพลิเคชัน Spring โดยใช้ Redis คุณจะเดินผ่านแอปพลิเคชันตัวอย่างที่บริการหนึ่งกำลังผลักดันเหตุการณ์ในคิวและอีกบริการหนึ่งกำลังประมวลผลเหตุการณ์เหล่านี้ทีละรายการ
โครงการ Spring Integration ขยายกรอบ Spring เพื่อให้การสนับสนุนการส่งข้อความระหว่างหรือภายในแอปพลิเคชันที่ใช้ Spring ส่วนประกอบต่างๆเชื่อมต่อกันผ่านกระบวนทัศน์การส่งข้อความ ส่วนประกอบส่วนบุคคลอาจไม่ทราบถึงส่วนประกอบอื่น ๆ ในแอปพลิเคชัน
Spring Integration มีกลไกมากมายในการสื่อสารกับระบบภายนอก อะแด็ปเตอร์ช่องสัญญาณเป็นกลไกหนึ่งที่ใช้สำหรับการรวมทางเดียว (ส่งหรือรับ) และเกตเวย์ใช้สำหรับสถานการณ์การร้องขอ / ตอบกลับ (ขาเข้าหรือขาออก)
Apache Camel เป็นอีกทางเลือกหนึ่งที่ใช้กันอย่างแพร่หลาย โดยปกติแล้วการรวมสปริงเป็นที่ต้องการในบริการที่ใช้สปริงที่มีอยู่เนื่องจากเป็นส่วนหนึ่งของระบบนิเวศของสปริง
Redis เป็นที่เก็บข้อมูลในหน่วยความจำที่รวดเร็วมาก สามารถเลือกที่จะคงอยู่ในดิสก์ได้เช่นกัน สนับสนุนโครงสร้างข้อมูลที่แตกต่างกันเช่นคู่คีย์ - ค่าอย่างง่ายชุดคิว ฯลฯ
การใช้ Redis เป็นคิวทำให้การแชร์ข้อมูลระหว่างส่วนประกอบและการปรับขนาดแนวนอนทำได้ง่ายขึ้นมาก ผู้ผลิตหรือผู้ผลิตหลายรายสามารถส่งข้อมูลไปยังคิวและผู้บริโภคหรือผู้บริโภคหลายรายสามารถดึงข้อมูลและประมวลผลเหตุการณ์ได้
ผู้บริโภคหลายรายไม่สามารถใช้เหตุการณ์เดียวกันได้ซึ่งจะทำให้แน่ใจได้ว่ามีการประมวลผลเหตุการณ์หนึ่งครั้ง
ประโยชน์ของการใช้ Redis เป็นคิวข้อความ:
กฎ:
ต่อไปนี้จะอธิบายถึงการสร้างแอปพลิเคชันตัวอย่างเพื่ออธิบายวิธีใช้ Spring Integration กับ Redis
สมมติว่าคุณมีแอปพลิเคชันที่อนุญาตให้ผู้ใช้เผยแพร่โพสต์ และคุณต้องการสร้างคุณลักษณะการติดตาม ข้อกำหนดอีกประการหนึ่งคือทุกครั้งที่มีคนเผยแพร่โพสต์ผู้ติดตามทุกคนควรได้รับแจ้งผ่านช่องทางการสื่อสารบางช่องทาง (เช่นอีเมลหรือข้อความ Push)
วิธีหนึ่งในการนำไปใช้คือการส่งอีเมลไปยังผู้ติดตามแต่ละคนเมื่อผู้ใช้เผยแพร่บางสิ่ง แต่จะเกิดอะไรขึ้นเมื่อผู้ใช้มีผู้ติดตาม 1,000 คน? และเมื่อผู้ใช้ 1,000 คนเผยแพร่บางสิ่งใน 10 วินาทีแต่ละคนมีผู้ติดตาม 1,000 คน? นอกจากนี้โพสต์ของผู้เผยแพร่จะรอจนกว่าอีเมลทั้งหมดจะถูกส่งหรือไม่
ระบบแบบกระจายช่วยแก้ไขปัญหานี้
ปัญหาเฉพาะนี้สามารถแก้ไขได้โดยใช้คิว บริการ A (ผู้ผลิต) ซึ่งรับผิดชอบในการเผยแพร่โพสต์จะดำเนินการดังกล่าว จะเผยแพร่โพสต์และพุชกิจกรรมพร้อมรายชื่อผู้ใช้ที่ต้องรับอีเมลและโพสต์นั้นเอง รายชื่อผู้ใช้สามารถดึงได้จากบริการ B แต่เพื่อความง่ายของตัวอย่างนี้เราจะส่งจากบริการ A
นี่คือการดำเนินการแบบอะซิงโครนัส ซึ่งหมายความว่าบริการที่เผยแพร่จะไม่ต้องรอส่งอีเมล
แอปสาธิตวัสดุเชิงมุม 2
บริการ B (ผู้บริโภค) จะดึงเหตุการณ์ออกจากคิวและดำเนินการ ด้วยวิธีนี้เราสามารถปรับขนาดบริการของเราได้อย่างง่ายดายและเรามี n
ผู้บริโภคส่งอีเมล (ประมวลผลเหตุการณ์)
เริ่มต้นด้วยการนำไปใช้ในบริการของผู้ผลิต การอ้างอิงที่จำเป็น ได้แก่ :
redis.clients jedis org.springframework.data spring-data-redis org.springframework.integration spring-integration-redis
การพึ่งพา Maven ทั้งสามนี้จำเป็น:
ต่อไปเราต้องกำหนดค่าไคลเอนต์ Jedis:
@Configuration public class RedisConfig { @Value('${redis.host}') private String redisHost; @Value('${redis.port:6379}') private int redisPort; @Bean public JedisPoolConfig poolConfig() { JedisPoolConfig poolConfig = new JedisPoolConfig(); poolConfig.setMaxTotal(128); return poolConfig; } @Bean public RedisConnectionFactory redisConnectionFactory(JedisPoolConfig poolConfig) { final JedisConnectionFactory connectionFactory = new JedisConnectionFactory(); connectionFactory.setHostName(redisHost); connectionFactory.setPort(redisPort); connectionFactory.setPoolConfig(poolConfig); connectionFactory.setUsePool(true); return connectionFactory; } }
คำอธิบายประกอบ @Value
หมายความว่า Spring จะฉีดค่าที่กำหนดไว้ในคุณสมบัติของแอปพลิเคชันลงในฟิลด์ ซึ่งหมายความว่า redis.host
และ redis.port
ควรกำหนดค่าในคุณสมบัติของแอปพลิเคชัน
ตอนนี้เราต้องกำหนดข้อความที่เราต้องการส่งไปยังคิว ข้อความตัวอย่างง่ายๆอาจมีลักษณะดังนี้:
@Getter @Setter @Builder public class PostPublishedEvent { private String postUrl; private String postTitle; private List emails; }
หมายเหตุ: โครงการลอมบอก ( https://projectlombok.org/ ) ให้ @Getter
, @Setter
, @Builder
และคำอธิบายประกอบอื่น ๆ อีกมากมายเพื่อหลีกเลี่ยงไม่ให้โค้ดเกะกะด้วย getters, setters และสิ่งเล็กน้อยอื่น ๆ คุณสามารถเรียนรู้เพิ่มเติมได้จาก บทความ ApeeScape นี้ .
เมื่อทำการนำเสนอที่ซับซ้อนซึ่งต่อไปนี้
ข้อความจะถูกบันทึกในรูปแบบ JSON ในคิว ทุกครั้งที่มีการเผยแพร่เหตุการณ์ไปยังคิวข้อความจะถูกจัดลำดับเป็น JSON และเมื่อใช้งานจากคิวข้อความจะถูก deserialized
ด้วยข้อความที่กำหนดเราจำเป็นต้องกำหนดคิวเอง ใน Spring Integration สามารถทำได้อย่างง่ายดายผ่านทาง .xml
การกำหนดค่า ควรวางการกำหนดค่าไว้ใน resources/WEB-INF
ไดเรกทอรี
MessageChannel
ในการกำหนดค่าคุณจะเห็นส่วน“ int-redis: que-outbound-channel-adapter” คุณสมบัติของมันคือ:
RedisConnectionFactory
ซึ่งปลายทางนี้ได้รับข้อความ#root
ถั่ว.RedisSerializer
ตัวแปร. แอตทริบิวต์นี้ใช้ร่วมกันกับคิวJdkSerializationRedisSerializer
การอ้างอิงถั่ว โดยค่าเริ่มต้นจะเป็น String
อย่างไรก็ตามสำหรับ StringRedisSerializer
payloads, a true
จะใช้หากไม่มีการอ้างอิงซีเรียลไลเซอร์true
false
) หรือกดขวา (เมื่อ false
) เพื่อเขียนข้อความไปยังรายการ Redis ถ้าเป็นจริงรายการ Redis จะทำหน้าที่เป็นคิว FIFO เมื่อใช้กับอะแด็ปเตอร์ช่องสัญญาณขาเข้าของคิว Redis เริ่มต้น ตั้งค่าเป็น true
เพื่อใช้กับซอฟต์แวร์ที่อ่านจากรายการด้วยป๊อปด้านซ้ายหรือเพื่อให้ได้ลำดับข้อความแบบสแต็ก ค่าเริ่มต้นคือ .xml
ขั้นตอนต่อไปคือการกำหนดเกตเวย์ซึ่งกล่าวถึงใน RedisChannelGateway
การกำหนดค่า สำหรับเกตเวย์เรากำลังใช้ org.toptal.queue
คลาสจาก StringRedisSerializer
แพ็คเกจ
.xml
ใช้เพื่อจัดลำดับข้อความก่อนบันทึกใน Redis นอกจากนี้ใน RedisChannelGateway
เรากำหนดเกตเวย์และตั้งค่า RedisChannelGateway
เป็นบริการเกตเวย์ ซึ่งหมายความว่า default-request-channel
ถั่วสามารถฉีดเข้าไปในถั่วอื่น ๆ ได้ เรากำหนดคุณสมบัติ @Gateway
เนื่องจากยังสามารถให้การอ้างอิงแชนเนลต่อวิธีได้โดยใช้ public interface RedisChannelGateway { void enqueue(PostPublishedEvent event); }
คำอธิบายประกอบ นิยามคลาส:
SpringIntegrationConfig
ในการเชื่อมต่อการกำหนดค่านี้เข้ากับแอปพลิเคชันของเราเราต้องนำเข้า สิ่งนี้ถูกนำไปใช้ใน @ImportResource('classpath:WEB-INF/event-queue-config.xml') @AutoConfigureAfter(RedisConfig.class) @Configuration public class SpringIntegrationConfig { }
ชั้นเรียน
@ImportResource
.xml
คำอธิบายประกอบใช้เพื่อนำเข้า Spring @Configuration
ไฟล์กำหนดค่าเป็น @AutoConfigureAfter
. และ enqueue
คำอธิบายประกอบใช้เพื่อบอกใบ้ว่าควรใช้การกำหนดค่าอัตโนมัติหลังคลาสการกำหนดค่าอัตโนมัติอื่น ๆ ที่ระบุ
ตอนนี้เราจะสร้างบริการและใช้วิธีการที่จะ public interface QueueService { void enqueue(PostPublishedEvent event); }
เหตุการณ์ไปยังคิว Redis
@Service public class RedisQueueService implements QueueService { private RedisChannelGateway channelGateway; @Autowired public RedisQueueService(RedisChannelGateway channelGateway) { this.channelGateway = channelGateway; } @Override public void enqueue(PostPublishedEvent event) { channelGateway.enqueue(event); } }
enqueue
และตอนนี้คุณสามารถส่งข้อความไปยังคิวได้อย่างง่ายดายโดยใช้ QueueService
วิธีการจาก LPUSH
.
apache spark ทำงานอย่างไร
คิว Redis เป็นเพียงรายการของผู้ผลิตและผู้บริโภคหนึ่งรายขึ้นไป ในการเผยแพร่ข้อความไปยังคิวโปรดิวเซอร์ใช้ redis-cli monitor
คำสั่ง Redis และหากคุณตรวจสอบ Redis (คำใบ้: พิมพ์ 'LPUSH' 'my-event-queue' '{'postUrl':'test','postTitle':'test','emails':['test']}'
) คุณจะเห็นว่ามีการเพิ่มข้อความลงในคิว:
PostPublishedEvent
ตอนนี้เราต้องสร้างแอปพลิเคชันสำหรับผู้บริโภคซึ่งจะดึงเหตุการณ์เหล่านี้ออกจากคิวและประมวลผล บริการผู้บริโภคต้องการการอ้างอิงเช่นเดียวกับบริการผู้ผลิต
ตอนนี้เราสามารถนำ resources/WEB-INF
คลาสเพื่อยกเลิกการเชื่อมต่อข้อความ
เราจำเป็นต้องสร้างการกำหนดค่าคิวและอีกครั้งจะต้องวางไว้ใน .xml
ไดเรกทอรี เนื้อหาของการกำหนดค่าคิวคือ:
int-redis:queue-inbound-channel-adapter
ใน MessageChannel
การกำหนดค่า, SmartLifecycle
สามารถมีคุณสมบัติดังต่อไปนี้:
true
ซึ่งเราส่งข้อความจากปลายทางนี้SmartLifecycle
แอตทริบิวต์เพื่อระบุว่าจุดสิ้นสุดนี้ควรเริ่มต้นโดยอัตโนมัติหลังจากเริ่มบริบทของแอปพลิเคชันหรือไม่ ค่าเริ่มต้นคือ 0
RedisConnectionFactory
แอตทริบิวต์เพื่อระบุเฟสที่จะเริ่มต้นจุดสิ้นสุดนี้ ค่าเริ่มต้นคือ MessageChannel
ErrorMessages
ถั่ว.Exceptions
ที่เราจะส่ง Endpoint
ด้วย MessagePublishingErrorHandler
จากงานการฟังของ errorChannel
. โดยค่าเริ่มต้นพื้นฐาน RedisSerializer
ใช้ค่าเริ่มต้น byte[]
จากบริบทของแอปพลิเคชันMessage
การอ้างอิงถั่ว อาจเป็นสตริงว่างซึ่งหมายความว่าไม่มีซีเรียลไลเซอร์ ในกรณีนี้ดิบ JdkSerializationRedisSerializer
จากข้อความ Redis ขาเข้าจะถูกส่งไปยังช่องเป็น true
น้ำหนักบรรทุก โดยค่าเริ่มต้นจะเป็น false
TaskExecutor
ซีเรียลไลเซอร์ต้องไม่เป็นสตริงว่างเนื่องจากข้อความต้องการรูปแบบการดีซีเรียลไลเซชันบางรูปแบบ (การทำให้อนุกรม JDK โดยค่าเริ่มต้น) ค่าเริ่มต้นคือ SimpleAsyncTaskExecutor
true
(หรือมาตรฐาน JDK 1.5+ Executor) bean ใช้สำหรับงานการฟังพื้นฐาน โดยค่าเริ่มต้น a false
ถูกนำมาใช้.true
) หรือป๊อปด้านซ้าย (เมื่อ false
) เพื่ออ่านข้อความจากรายการ Redis ถ้า true
รายการ Redis จะทำหน้าที่เป็นคิว FIFO เมื่อใช้กับอะแด็ปเตอร์ช่องสัญญาณขาออก Redis เริ่มต้น ตั้งค่าเป็น json-to-object-transformer
เพื่อใช้กับซอฟต์แวร์ที่เขียนลงในรายการด้วยการกดขวาหรือเพื่อให้ได้ลำดับข้อความแบบสแตก ค่าเริ่มต้นคือ type='com.toptal.integration.spring.model.PostPublishedEvent'
ส่วนที่สำคัญคือ 'ตัวกระตุ้นบริการ' ซึ่งกำหนดว่าควรใช้บริการและวิธีการใดในการดำเนินการกับเหตุการณ์
นอกจากนี้ SpringIntegrationConfig
ต้องการแอตทริบิวต์ประเภทเพื่อเปลี่ยน JSON เป็นวัตถุตั้งค่าด้านบนเป็น public interface EventProcessingService { void process(PostPublishedEvent event); } @Service('RedisEventProcessingService') public class RedisEventProcessingService implements EventProcessingService { @Override public void process(PostPublishedEvent event) { // TODO: Send emails here, retry strategy, etc :) } }
อีกครั้งในการเชื่อมต่อการกำหนดค่านี้เราจะต้องมี 'BRPOP' 'my-event-queue' '1'
ซึ่งอาจจะเหมือนกับก่อนหน้านี้ และประการสุดท้ายเราต้องการบริการที่จะดำเนินการตามเหตุการณ์
|_+_|
เมื่อคุณเรียกใช้แอปพลิเคชันคุณจะเห็นใน Redis:
|_+_|
ด้วย Spring Integration และ Redis การสร้างแอปพลิเคชัน Spring microservices นั้นไม่น่ากลัวอย่างที่เคยเป็นมา ด้วยการกำหนดค่าเล็กน้อยและรหัสสำเร็จรูปจำนวนเล็กน้อยคุณสามารถสร้างรากฐานของสถาปัตยกรรมไมโครเซอร์วิสได้ในเวลาอันรวดเร็ว
แม้ว่าคุณจะไม่ได้วางแผนที่จะขูดโครงการ Spring ปัจจุบันของคุณทั้งหมดและเปลี่ยนไปใช้สถาปัตยกรรมใหม่ด้วยความช่วยเหลือของ Redis แต่ก็เป็นเรื่องง่ายมากที่จะได้รับการปรับปรุงประสิทธิภาพครั้งใหญ่ด้วยคิว
แอพพลิเคชั่นที่ใช้ไมโครเซอร์วิสคือระบบกระจายที่ทำงานบนเครื่องหลายเครื่อง แต่ละบริการในระบบสื่อสารโดยส่งข้อความไปยังผู้อื่น
ในแอปพลิเคชันเสาหินส่วนประกอบทั้งหมดจะอยู่ในกระบวนการเดียวกันและโดยปกติการสื่อสารจะขึ้นอยู่กับการเรียกใช้วิธีการหรือฟังก์ชันภายในกระบวนการเดียวกัน