কম্পিউটার টিউটোরিয়াল

Bucket4J এবং Redis-এর সাথে স্কেলেবল রেট লিমিটিং প্রয়োগ করুন - ধাপে ধাপে নির্দেশিকা

Bucket4J এবং Redis-এর সাথে স্কেলেবল রেট লিমিটিং প্রয়োগ করুন - ধাপে ধাপে নির্দেশিকা

এই টিউটোরিয়ালে আমরা শিখব কিভাবে একটি স্কেল করা পরিষেবাতে রেট লিমিটিং প্রয়োগ করতে হয়।
আমরা এটি বাস্তবায়ন করতে Bucket4J লাইব্রেরি ব্যবহার করব এবং আমরা Redis কে একটি বিতরণ করা ক্যাশে হিসেবে ব্যবহার করব।

কেন রেট লিমিটিং ব্যবহার করবেন?

আসুন আমরা হার সীমিত করার প্রয়োজনীয়তা বুঝতে পারি এবং এই টিউটোরিয়ালে আমরা যে সরঞ্জামগুলি ব্যবহার করব তা নিশ্চিত করার জন্য কিছু বেসিক দিয়ে শুরু করি৷

সীমাহীন হারে সমস্যা

যদি টুইটার API-এর মতো একটি পাবলিক API তার ব্যবহারকারীদের প্রতি ঘন্টায় সীমাহীন সংখ্যক অনুরোধ করার অনুমতি দেয়, তাহলে এটি হতে পারে:

  • সম্পদ নিষ্কাশন
  • পরিষেবার মান হ্রাস করা
  • পরিষেবা আক্রমণ অস্বীকার

এর ফলে এমন পরিস্থিতি হতে পারে যেখানে পরিষেবা অনুপলব্ধ বা ধীর৷ . এটি আরও অপ্রত্যাশিত খরচ হতে পারে পরিষেবা দ্বারা ব্যয় করা হচ্ছে৷

হার সীমাবদ্ধতা কিভাবে সাহায্য করে

প্রথমত, হার-সীমাবদ্ধতা পরিষেবা আক্রমণ অস্বীকার করতে পারে। ডিডপ্লিকেশন মেকানিজম বা API কীগুলির সাথে মিলিত হলে, হার সীমিত করা পরিষেবা আক্রমণের বিতরণ অস্বীকার রোধ করতেও সাহায্য করতে পারে৷

দ্বিতীয়ত, এটি ট্রাফিক অনুমান করতে সাহায্য করে। পাবলিক API-এর জন্য এটি খুবই গুরুত্বপূর্ণ। এটি পরিষেবাটি নিরীক্ষণ এবং স্কেল করার জন্য স্বয়ংক্রিয় স্ক্রিপ্টগুলির সাথেও মিলিত হতে পারে৷

এবং তৃতীয়ত, আপনি এটি টিয়ার-ভিত্তিক মূল্য প্রয়োগ করতে ব্যবহার করতে পারেন। এই ধরনের মূল্যের মডেলের অর্থ হল ব্যবহারকারীরা অনুরোধের উচ্চ হারের জন্য অর্থ প্রদান করতে পারেন। Twitter API এর একটি উদাহরণ৷

টোকেন বাকেট অ্যালগরিদম

টোকেন বাকেট হল একটি অ্যালগরিদম যা আপনি হার সীমিত করার জন্য ব্যবহার করতে পারেন। সংক্ষেপে, এটি নিম্নরূপ কাজ করে:

  1. একটি বালতি একটি নির্দিষ্ট ক্ষমতা (টোকেনের সংখ্যা) সহ তৈরি করা হয়।
  2. যখন একটি অনুরোধ আসে, বালতি চেক করা হয়। যদি যথেষ্ট ক্ষমতা থাকে, অনুরোধটি এগিয়ে যাওয়ার অনুমতি দেওয়া হয়। অন্যথায়, অনুরোধটি প্রত্যাখ্যান করা হয়৷
  3. একটি অনুরোধ অনুমোদিত হলে, ক্ষমতা হ্রাস করা হয়।
  4. একটি নির্দিষ্ট সময় পরে, ক্ষমতা পুনরায় পূরণ করা হয়।

ডিস্ট্রিবিউটেড সিস্টেমে টোকেন বাকেট কিভাবে প্রয়োগ করবেন

একটি বিতরণ করা সিস্টেমে টোকেন বাকেট অ্যালগরিদম বাস্তবায়ন করতে, আমাদের একটি ডিস্ট্রিবিউটেড ক্যাশে ব্যবহার করতে হবে .

ক্যাশে হল একটি কী-মানের দোকান বালতি তথ্য সংরক্ষণ করতে. আমরা এটি বাস্তবায়ন করতে একটি Redis ক্যাশে ব্যবহার করব৷

অভ্যন্তরীণভাবে, Bucket4j আমাদের জাভা JCache API-এর যেকোনো বাস্তবায়ন প্লাগ-ইন করতে দেয়। Redis এর Redisson ক্লায়েন্ট হল বাস্তবায়ন আমরা ব্যবহার করব।

প্রকল্প বাস্তবায়ন

আমরা আমাদের পরিষেবা তৈরি করতে স্প্রিং বুট ফ্রেমওয়ার্ক ব্যবহার করব।

আমাদের পরিষেবাতে নিম্নলিখিত উপাদানগুলি থাকবে:

  1. একটি সাধারণ REST API।
  2. পরিষেবার সাথে সংযুক্ত একটি রেডিস ক্যাশে – রেডিসন ক্লায়েন্ট ব্যবহার করে।
  3. Bucket4J লাইব্রেরি REST API এর চারপাশে মোড়ানো।
  4. আমরা Bucket4J কে JCache ইন্টারফেসের সাথে সংযুক্ত করব যা পটভূমিতে বাস্তবায়ন হিসাবে Redisson ক্লায়েন্ট ব্যবহার করবে।

প্রথমত, আমরা সকল অনুরোধের জন্য API সীমিত হার করতে শিখব। তারপরে আমরা প্রতি ব্যবহারকারী বা প্রতি মূল্য স্তরের জন্য আরও জটিল হার সীমিত করার পদ্ধতি প্রয়োগ করতে শিখব।

প্রজেক্ট সেটআপ দিয়ে শুরু করা যাক।

নির্ভরতা ইনস্টল করুন

আসুন আমাদের pom.xml-এ নীচের নির্ভরতা যোগ করি (বা build.gradle ) ফাইল।

<dependencies>
 <!-- To build the Rest API -->
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <!-- Redisson Starter = Spring Data Redis starter(excluding other clients) and Redisson client -->
 <dependency>
 <groupId>org.redisson</groupId>
 <artifactId>redisson-spring-boot-starter</artifactId>
 <version>3.17.0</version>
 </dependency>
 <!-- Bucket4J starter = Bucket4J + JCache -->
 <dependency>
 <groupId>com.giffing.bucket4j.spring.boot.starter</groupId>
 <artifactId>bucket4j-spring-boot-starter</artifactId>
 <version>0.5.2</version>
 </dependency>
</dependencies>

ক্যাশ কনফিগারেশন

প্রথমত, আমাদের রেডিস সার্ভার শুরু করতে হবে। ধরা যাক আমাদের স্থানীয় মেশিনে পোর্ট 6379 এ চলমান একটি Redis সার্ভার রয়েছে৷

আমাদের দুটি ধাপ সম্পাদন করতে হবে:

  1. আমাদের অ্যাপ্লিকেশন থেকে এই সার্ভারের সাথে একটি সংযোগ তৈরি করুন৷
  2. ইমপ্লিমেন্টেশন হিসেবে Redisson ক্লায়েন্ট ব্যবহার করতে JCache সেট আপ করুন।

রেডিসনের ডকুমেন্টেশন নিয়মিত জাভা অ্যাপ্লিকেশনে এটি বাস্তবায়নের জন্য সংক্ষিপ্ত পদক্ষেপ প্রদান করে। আমরা একই পদক্ষেপগুলি বাস্তবায়ন করতে যাচ্ছি, কিন্তু স্প্রিং বুটে৷

আসুন প্রথমে কোডটি দেখি। প্রয়োজনীয় মটরশুটি তৈরি করতে আমাদের একটি কনফিগারেশন ক্লাস তৈরি করতে হবে।

@Configuration
public class RedisConfig {
 @Bean
 public Config config() {
 Config config = new Config();
 config.useSingleServer().setAddress("redis://localhost:6379");
 return config;
 }
 @Bean
 public CacheManager cacheManager(Config config) {
 CacheManager manager = Caching.getCachingProvider().getCacheManager();
 cacheManager.createCache("cache", RedissonConfiguration.fromConfig(config));
 return cacheManager;
 }
 @Bean
 ProxyManager<String> proxyManager(CacheManager cacheManager) {
 return new JCacheProxyManager<>(cacheManager.getCache("cache"));
 }
}

এটি কী করে?

  1. একটি কনফিগারেশন অবজেক্ট তৈরি করে যা আমরা একটি সংযোগ তৈরি করতে ব্যবহার করতে পারি।
  2. কনফিগারেশন অবজেক্ট ব্যবহার করে একটি ক্যাশে ম্যানেজার তৈরি করে। এটি অভ্যন্তরীণভাবে Redis উদাহরণের সাথে একটি সংযোগ তৈরি করবে এবং এটিতে "ক্যাশে" নামে একটি হ্যাশ তৈরি করবে৷
  3. একটি প্রক্সি ম্যানেজার তৈরি করে যা ক্যাশে অ্যাক্সেস করতে ব্যবহার করা হবে। আমাদের অ্যাপ্লিকেশন JCache API ব্যবহার করে ক্যাশে করার চেষ্টা করে না কেন, এটি "ক্যাশে" নামের হ্যাশের ভিতরে রেডিস ইন্সট্যান্সে ক্যাশে করা হবে।

এপিআই তৈরি করুন

আসুন একটি সাধারণ REST API তৈরি করি।

@RestController
public class RateLimitController {
 @GetMapping("/user/{id}")
 public String getInfo(@PathVariable("id") String id) {
 return "Hello " + id;
 }
}

যদি আমি URL http://localhost:8080/user/1 দিয়ে API এ আঘাত করি , আমি Hello 1 প্রতিক্রিয়া পাব .

Bucket4J কনফিগারেশন

হার সীমিত বাস্তবায়ন করতে, আমাদের Bucket4J কনফিগার করতে হবে। সৌভাগ্যক্রমে, স্টার্টার লাইব্রেরির কারণে আমাদের কোনো বয়লারপ্লেট কোড লিখতে হবে না।

এছাড়াও এটি স্বয়ংক্রিয়ভাবে ProxyManager বিন সনাক্ত করে আমরা পূর্ববর্তী ধাপে তৈরি করেছি এবং বালতি ক্যাশে করতে এটি ব্যবহার করেছি।

আমাদের যা করতে হবে তা হল এই লাইব্রেরিটি আমাদের তৈরি করা API এর চারপাশে কনফিগার করুন।
আবার এটি করার একাধিক উপায় রয়েছে৷

আমরা সম্পত্তি-ভিত্তিক কনফিগারেশনের জন্য যেতে পারি যা স্টার্টার লাইব্রেরিতে সংজ্ঞায়িত করা হয়েছে।
সব ব্যবহারকারী বা সমস্ত অতিথি ব্যবহারকারীদের জন্য হার-সীমাবদ্ধ করার মতো সাধারণ ক্ষেত্রে এটি সবচেয়ে সুবিধাজনক উপায়।

যাইহোক, যদি আমরা প্রতিটি ব্যবহারকারীর জন্য একটি হারের সীমার মতো আরও জটিল কিছু বাস্তবায়ন করতে চাই, তাহলে এটির জন্য কাস্টম কোড লেখাই ভালো৷

আমরা প্রতি ব্যবহারকারীর হার সীমিত বাস্তবায়ন করতে যাচ্ছি। ধরা যাক আমাদের কাছে প্রতিটি ব্যবহারকারীর জন্য একটি ডাটাবেসে সংরক্ষিত হারের সীমা রয়েছে এবং আমরা ব্যবহারকারী আইডি ব্যবহার করে এটি অনুসন্ধান করতে পারি।

এর জন্য ধাপে ধাপে কোড লিখি।

একটি বালতি তৈরি করুন

আমরা শুরু করার আগে, আসুন দেখি কিভাবে একটি বালতি তৈরি হয়।

Refill refill = Refill.intervally(10, Duration.ofMinutes(1));
Bandwidth limit = Bandwidth.classic(10, refill);
Bucket bucket = Bucket4j.builder()
 .addLimit(limit)
 .build();
  • রিফিল – কতক্ষণ পরে বালতিটি রিফিল করা হবে।
  • ব্যান্ডউইথ - বালতিতে কত ব্যান্ডউইথ আছে। মূলত, রিফিল পিরিয়ড প্রতি অনুরোধ।
  • বালতি - এই দুটি পরামিতি ব্যবহার করে কনফিগার করা একটি বস্তু। উপরন্তু, বালতিতে কতগুলি টোকেন পাওয়া যায় তার ট্র্যাক রাখতে এটি একটি টোকেন কাউন্টার বজায় রাখে৷

এটিকে বিল্ডিং ব্লক হিসাবে ব্যবহার করে, আসুন এটিকে আমাদের ব্যবহারের ক্ষেত্রে উপযুক্ত করার জন্য কয়েকটি জিনিস পরিবর্তন করি।

ProxyManager ব্যবহার করে বালতি তৈরি এবং ক্যাশে করুন

আমরা Redis এ বালতি সংরক্ষণের উদ্দেশ্যে প্রক্সি ম্যানেজার তৈরি করেছি। একবার একটি বালতি তৈরি হয়ে গেলে, এটি Redis-এ ক্যাশে করা প্রয়োজন এবং আবার তৈরি করার প্রয়োজন নেই৷

এটি ঘটানোর জন্য, আমরা Bucket4j.builder() প্রতিস্থাপন করব proxyManager.builder() সহ . প্রক্সি ম্যানেজার বালতি ক্যাশে করার এবং সেগুলিকে আবার তৈরি না করার যত্ন নেবে৷

ProxyManager এর নির্মাতা দুটি প্যারামিটার নেয় – একটি কী যার বিরুদ্ধে বালতি ক্যাশে করা হবে এবং একটি কনফিগারেশন অবজেক্ট যা এটি বালতি তৈরি করতে ব্যবহার করবে।

আসুন দেখি কিভাবে আমরা এটি বাস্তবায়ন করতে পারি:

@Service
public class RateLimiter {
 //autowiring dependencies
 public Bucket resolveBucket(String key) {
 Supplier<BucketConfiguration> configSupplier = getConfigSupplierForUser(key);
 // Does not always create a new bucket, but instead returns the existing one if it exists.
 return buckets.builder().build(key, configSupplier);
 }
 private Supplier<BucketConfiguration> getConfigSupplierForUser(String key) {
 User user = userRepository.findById(userId);
 Refill refill = Refill.intervally(user.getLimit(), Duration.ofMinutes(1));
 Bandwidth limit = Bandwidth.classic(user.getLimit(), refill);
 return () -> (BucketConfiguration.builder()
 .addLimit(limit)
 .build());
 }
}

আমরা একটি পদ্ধতি তৈরি করেছি যা প্রদত্ত চাবির জন্য একটি বালতি প্রদান করে। পরবর্তী ধাপে, আমরা দেখব কিভাবে এটি ব্যবহার করতে হয়।

কিভাবে টোকেন ব্যবহার করবেন এবং রেট লিমিটিং সেট আপ করবেন

যখন একটি অনুরোধ আসে, আমরা প্রাসঙ্গিক বালতি থেকে একটি টোকেন গ্রহণ করার চেষ্টা করব৷
আমরা tryConsume() ব্যবহার করব এটি করার জন্য বালতির পদ্ধতি।

@GetMapping("/user/{id}")
public String getInfo(@PathVariable("id") String id) {
 // gets the bucket for the user
 Bucket bucket = rateLimiter.resolveBucket(id);
 // tries to consume a token from the bucket
 if (bucket.tryConsume(1)) {
 return "Hello " + id;
 } else {
 return "Rate limit exceeded";
 }
}

tryConsume() পদ্ধতি true প্রদান করে যদি টোকেনটি সফলভাবে ব্যবহার করা হয় অথবা false যদি টোকেন ব্যবহার না করা হয়।

কিভাবে আমাদের পরিষেবা পরীক্ষা করবেন

আমরা যেকোনো স্বয়ংক্রিয় পরীক্ষার কৌশল ব্যবহার করে এটি পরীক্ষা করতে পারি। উদাহরণস্বরূপ, আমরা JUnit ব্যবহার করতে পারি। আসুন একটি টেস্ট কেস লিখি যা getInfo() কল করে পদ্ধতি একাধিকবার এবং যাচাই করে যে প্রতিক্রিয়াটি সঠিক।

ধরা যাক আমাদের একজন ব্যবহারকারী আছে যার আইডি 1 আছে এবং 10 এর একটি সীমা প্রতি মিনিটে অনুরোধ। ধরা যাক আমাদেরও একজন ব্যবহারকারী আছে যার আইডি 2 আছে এবং 20 এর একটি সীমা প্রতি মিনিটে অনুরোধ।

আমরা উভয় ব্যবহারকারীর জন্য 11টি অনুরোধ করব এবং যাচাই করব যে আইডি 1 ব্যবহারকারীর জন্য অনুরোধ ব্যর্থ হয়েছে কিন্তু 2 আইডি সহ ব্যবহারকারীর জন্য সফল হয় .

@Test
public void testGetInfo() {
 // calls the method 10 times for user 1
 for (int i = 0; i < 10; i++) {
 rateLimiter.getInfo(1));
 rateLimiter.getInfo(2));
 }
 // verifies that the response is rate limited for user 1
 assertEquals("Rate limit exceeded", rateLimiter.getInfo(1));
 // verifies that the response is successful for user 2
 assertEquals("Hello 2", rateLimiter.getInfo(2));
}

যখন আমরা পরীক্ষা চালাব, তখন আমরা দেখব যে পরীক্ষা পাস হয়েছে।

উপসংহার

এই টিউটোরিয়ালে, আমরা একটি স্প্রিং বুট অ্যাপ্লিকেশনে Bucket4j এবং Redis ব্যবহার করে কীভাবে একটি রেট লিমিটার তৈরি করতে হয় তা কভার করেছি৷ আমরা কীভাবে JCache-এর সাথে একটি Redisson ক্লায়েন্ট সেট আপ করতে হয় এবং কীভাবে বালতি ক্যাশে করতে এটি ব্যবহার করতে হয় তাও দেখেছি৷

শেষ পর্যন্ত, আমরা একটি সাধারণ রেট লিমিটার প্রয়োগ করেছি যা নির্দিষ্ট ব্যবহারকারীদের জন্য অনুরোধ সীমা রেট দিতে ব্যবহার করা যেতে পারে।

আশা করি আপনি এই টিউটোরিয়ালটি উপভোগ করেছেন। পড়ার জন্য ধন্যবাদ!

বিনামূল্যে কোড শিখুন. freeCodeCamp-এর ওপেন সোর্স পাঠ্যক্রম 40,000-এরও বেশি লোককে ডেভেলপার হিসেবে চাকরি পেতে সাহায্য করেছে। শুরু করুন


  1. জাভাস্ক্রিপ্ট - মাউসের স্থানাঙ্ক পাওয়া

  2. জাভাস্ক্রিপ্টে মূল অ্যারে পরিবর্তন না করে কীভাবে একটি অবজেক্ট কী পরিবর্তন করবেন?

  3. কিভাবে সুইফট ব্যবহার করে UITableView এ নতুন সেল ঢোকাবেন?

  4. কীভাবে অ্যারেলিস্টকে অ্যান্ড্রয়েডে শেয়ার্ডপ্রেফারেন্সে সংরক্ষণ করবেন?