อัลกอริทึมตัว จำกัด ปัจจุบัน
ปัจจุบันมีอัลกอริธึมตัว จำกัด ปัจจุบันทั่วไปสองอัลกอริทึม: อัลกอริทึมถังโทเค็นและอัลกอริทึมถังรั่ว ความแตกต่างที่สำคัญคืออัลกอริทึมที่มีการรั่วไหลสามารถ จำกัด อัตราการร้องขอและการร้องขอการระเบิดที่ราบรื่นในขณะที่อัลกอริทึมถังโทเค็นอนุญาตให้มีการร้องขอการระเบิดจำนวนหนึ่งเมื่อ จำกัด อัตราเฉลี่ย
ด้านล่างนี้เป็นไดอะแกรมอัลกอริทึมสองรายการที่พบบนอินเทอร์เน็ตซึ่งสามารถแยกแยะได้อย่างง่ายดายจากลักษณะของอัลกอริทึมทั้งสองนี้
อัลกอริทึมการรั่วไหล
อัลกอริทึมถังโทเค็น
สำหรับอินเทอร์เฟซโดยทั่วไปจะได้รับการดำเนินการตามคำร้องขอการระเบิดจำนวนหนึ่งและจำเป็นต้องมีอัตราเฉลี่ยเท่านั้นที่จะ จำกัด ดังนั้นอัลกอริทึมถังโทเค็นจึงเป็นเรื่องธรรมดามากขึ้น
Token Bucket Algorithm Tool Ratelimiter
คลาสการใช้งาน Token Bucket Algorithm ที่ฉันใช้บ่อยที่สุดคือ Ratelimiter ของ Google Guava Guava ไม่เพียง แต่ใช้อัลกอริทึม Bucket Token เท่านั้น แต่ยังรวมถึงแคชคลาสคอลเลกชันใหม่คลาสเครื่องมือที่เกิดขึ้นพร้อมกันคลาสการประมวลผลสตริง ฯลฯ มันเป็นชุดเครื่องมือที่ทรงพลัง
Ratelimiter API สามารถดูการแนะนำของ Guava Ratelimiter ในเครือข่ายการเขียนโปรแกรมพร้อมกัน
การวิเคราะห์ซอร์สโค้ด Ratelimiter
โดยค่าเริ่มต้นแอตทริบิวต์หลักที่สุดของ Ratelimiter คือสอง NextFreeticketMicros เวลาโทเค็นสามารถรับได้ในครั้งต่อไปและจำนวนโทเค็นในที่เก็บเงินที่เก็บไว้
ตรวจสอบว่าจะได้รับโทเค็น:
ทุกครั้งที่คุณได้รับโทเค็นให้คำนวณเวลาที่เร็วที่สุดเพื่อรับโทเค็นในครั้งต่อไปตามจำนวนโทเค็นในถัง เมื่อพิจารณาว่าสามารถรับทรัพยากรได้หรือไม่เพียงเปรียบเทียบ NextFreeticketMicros กับเวลาปัจจุบัน
รับการดำเนินการโทเค็น:
สำหรับการได้รับโทเค็นให้คำนวณจำนวนโทเค็นใหม่ตาม NextFreeticketMicros และเวลาปัจจุบันให้เขียนหมายเลขโทเค็นโทเค็นปัจจุบันและคำนวณใหม่ NextFreeticketMicros หากมีโทเค็นในถังให้เขียนเวลาปัจจุบันและลดจำนวนโทเค็นที่ได้รับจากคำขอนี้
เช่นเดียวกับคลาส AQS ใน Java แกนกลางของ Ratelimiter คือวิธี Tryacquire
Public Boolean Tryacquire (ใบอนุญาต int, การหมดเวลายาว, หน่วย TimeUnit) {// พยายามที่จะได้รับเวลารอคอยสูงสุดเวลายาวนาน long TimeMicros = สูงสุด (unit.tomicros (หมดเวลา), 0); // ตรวจสอบว่าจำนวนทรัพยากรที่ได้รับนั้นถูกต้องที่ถูกต้อง (ใบอนุญาต); microstowait ยาว; // ล็อคซิงโครไนซ์ (mutex ()) {// เวลาปัจจุบันยาว nowmicros = stopwatch.readmicros (); // ตัดสินว่าสามารถรับทรัพยากรภายในเวลาหมดเวลาได้หรือไม่ถ้า (! canacquire (nowmicros, timeoutmicros)) {ส่งคืนเท็จ; } else {// ทรัพยากรสามารถรับคำนวณทรัพยากรใหม่และส่งคืนเวลาการนอนหลับที่ต้องการโดยเธรด microStowait ปัจจุบัน = ReserveAnDgetWaitLength (ใบอนุญาต, Nowmicros); }} // sleep stopwatch.sleepmicrosuninctably (microstowait); กลับมาจริง; -ตรวจสอบว่าจะได้รับโทเค็น:
บูลีนส่วนตัว canacquire (ยาว nowmicros, timeoutmicros ยาว) {// ในเวลาทรัพยากรที่เร็วที่สุดสามารถรับได้ - เวลารอ <= เวลาปัจจุบันสามารถรับได้ก่อนที่ทรัพยากรจะได้รับ return eareryearliestavailable (nowmicros) - TimeOutmicrosRatelimiter เริ่มต้นการใช้งานคลาส queryearliestavailable คือการใช้ตัวแปรสมาชิก NextFreeticketMicros
รับโทเค็นและคำนวณการดำเนินการรอเวลารอ:
Final Long ReserveEnDgetWaitLength (ใบอนุญาต int, Long Nowmicros) {// ได้รับเวลาในการรับช่วงเวลาต่อไปที่ยาวนาน = ReserveEarLiestAvailable (ใบอนุญาต, Nowmicros); // คำนวณเวลานอนที่จำเป็นสำหรับเธรดปัจจุบันเพื่อส่งคืนสูงสุด (momentavailable - nowmicros, 0);} Final Long ReservearLiestAvailable (Int ที่ต้องการ permits, long nowmicros) {// คำนวณจำนวนโทเค็นใหม่ในถังเก็บข้อมูล Resync (Nowmicros); Long ReturnValue = NextFreeticketMicros; // จำนวนโทเค็นที่ใช้ในครั้งนี้ Double StoredPerMitStospend = min (จำเป็นต้องใช้ permits, this.storedpermits); // คำนวณเวลาใหม่เพื่อให้ได้ในครั้งต่อไป NextFreeticketMicros double freshpermits = requirepermits - StoredPermitstospend; Long Waitmicros = StoredPermitStowaittime (this.storedpermits, StoredPermitStospend) + (ยาว) (FreshPermits * StableIntervalmicros); this.nextFreeticketMicros = longmath.saturatedAdd (NextFreeticketMicros, Waitmicros); // ลดจำนวนโทเค็นในถังนี้ StoredPermits -= StoredPermitStospend; returnValue; -ใช้สปริงสปริง MVC จำกัด การสกัดกั้น
ใช้ตัว handlerInterceptor สร้างตัว จำกัด กระแส ratelimiter ในตัวสร้าง
Public SimpleDerateLimitInterceptor (อัตรา int) {ถ้า (อัตรา> 0) GlobalRateLimiter = ratelimiter.create (อัตรา); อื่น ๆ โยน runtimeException ใหม่ ("อัตราจะต้องสูงกว่าศูนย์");}โทรหาวิธี tryacquire ของตัว จำกัด ปัจจุบันใน prehandle เพื่อตรวจสอบว่าอัตราการ จำกัด เกินกว่านั้น
Public Boolean Prehandle (คำขอ httpservletrequest, การตอบสนอง httpservletResponse, ตัวจัดการวัตถุ) โยนข้อยกเว้น {ถ้า (! globalRateLimiter.tryAcquire ()) {loggerutil.log (request.getRequesturi ()+ กลับเท็จ; } return true; -กำหนดค่า interceptor ขีด จำกัด ปัจจุบันใน dispatcher-servlet.xml
<MVC: interceptors> <!-interceptor ขีด จำกัด ปัจจุบัน-> <mvc: interceptor> <mvc: เส้นทางการแมป = "/**"/> <bean> <constructor-Arg index = "0" value = "$ {totalate}"เวอร์ชันที่ซับซ้อนของสปริง MVC Interceptor ขีด จำกัด ปัจจุบัน
ใช้คุณสมบัติเพื่อส่งผ่านในนิพจน์ URL ที่สกัดกั้น -> อัตราอัตรา
<MVC: interceptor> <mvc: path mapping = "/**"/> <bean> <!-URL ขีด จำกัด ปัจจุบัน-> <property name = "urlproperties"> <props> <prop key = "get/{id}"> 1 </prop> สร้างตัว จำกัด กระแส Ratelimiter ที่สอดคล้องกันสำหรับการแสดงออกของ URL แต่ละครั้ง นิพจน์ URL ถูกห่อหุ้มเป็น org.springframework.web.servlet.mvc.condition.patternsrequestcondition PatternSrequestCondition เป็นคลาสที่ใช้ใน DispatchERServlet ของ SpringMVC เพื่อจับคู่คำขอและตัวควบคุม สามารถตรวจสอบได้ว่าคำขอเป็นไปตามนิพจน์ URL เหล่านี้หรือไม่
ในวิธี prehandle interceptor
// เส้นทางการร้องขอปัจจุบัน String lookuppath = urlPathHelper.getLookuppathForRequest (คำขอ); // ซ้ำไปกว่ารูปแบบการแก้ไขปัญหาที่สอดคล้องกับนิพจน์ URL ทั้งหมด PatternSrequestCondition.getMatchingPatterns (lookuppath); if (! matches.isempty ()) {// ถ้าการแข่งขันสำเร็จให้รับโทเค็นของตัว จำกัด ปัจจุบันที่สอดคล้องกันถ้า (urlratemap.get (patternsrequestcondition). tryacquire ()) {loggerutil.log (lookuppath + " Limiter "); } else {// ไม่สามารถรับโทเค็น loggerutil.log (lookuppath + "คำขอเกิน" + joiner.on (","). เข้าร่วม (patternsrequestCondition.getPatterns ()) + "อัตรา จำกัด ปัจจุบัน"); กลับเท็จ; -คลาสการใช้งานเฉพาะ
โปรดดู GitHub
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น