This article mainly studies RateLimit - the relevant content of using guava to perform interface flow restriction, as follows.
1. Problem description
One day, Mr. A suddenly found that the number of requests for his interface suddenly increased to 10 times the previous one. Not long after, the interface was almost unusable and triggered a chain reaction that caused the entire system to collapse. How to deal with this situation? Life gives us the answer: for example, old-fashioned switches are equipped with fuses. Once someone uses super high-power equipment, the fuse will be blown to protect each appliance from being burned by strong current. Similarly, our interface also needs to be installed with a "fuse" to prevent the system paralysis caused by excessive pressure on the system by unanticipated requests. When the traffic is too large, mechanisms such as rejection or drainage can be adopted.
2. Commonly used current limiting algorithms
There are two commonly used current limiting algorithms: leaky bucket algorithm and token bucket algorithm.
The idea of the leaking bucket algorithm is very simple. Please enter the leaking bucket first. The leaking bucket will come out at a certain speed. When the water request is too large, it will directly overflow. It can be seen that the leaking bucket algorithm can forcibly limit the data transmission rate.
Figure 1 Schematic diagram of leaked bucket algorithm
For many application scenarios, in addition to being able to limit the average transmission rate of data, it is also required to allow some degree of burst transmission. At this time, the leaked bucket algorithm may not be suitable, and the token bucket algorithm is more suitable. As shown in Figure 2, the principle of the token bucket algorithm is that the system will put a token into the bucket at a constant speed. If the request needs to be processed, it is necessary to obtain a token from the bucket first. When there is no token in the bucket, service will be denied.
Figure 2 Schematic diagram of token bucket algorithm
3. RateLimiter in the current limiting tool class
Google's open source toolkit guava provides the RateLimiter class, which is based on the "token bucket algorithm" and is very convenient to use. For the specific use of this class interface, please refer to the RateLimiter usage practice.
RateLimiter Using Demo
package ratelimite;import com.google.common.util.concurrent.RateLimiter;public class RateLimiterDemo {public static void main(String[] args) {testNoRateLimiter();testWithRateLimiter();}public static void testNoRateLimiter() {long start = System.currentTimeMillis();for (int i = 0; i < 10; i++) {System.out.println("call execute.." + i);}long end = System.currentTimeMillis();System.out.println(end - start);}public static void testWithRateLimiter() {long start = System.currentTimeMillis();RateLimiter limiter = RateLimiter.create(10.0);// No more than 10 tasks per second are submitted for (int i = 0; i < 10; i++) {limiter.acquire();// Request RateLimiter, exceeding permits will be blocked System.out.println("call execute.." + i);}long end = System.currentTimeMillis();System.out.println(end - start);}} Four Guava concurrency: ListenableFuture and RateLimiter example
concept
ListenableFuture, as the name implies, is a future that can be listened to, it is an extended enhancement to Java native Future. We know that Future represents an asynchronous calculation task, and the calculation results can be obtained when the task is completed. If we want to get the results and display them to the user once the calculation is completed or do other calculations, we must use another thread to constantly query the calculation status. This makes the code complex and inefficient. Use ListenableFuture Guava to help us detect whether Future is completed. If it is completed, the callback function will be automatically called, which can reduce the complexity of the concurrent program.
The second method is recommended, because the second method can directly obtain the return value of Future or handle errors. In essence, the second method is achieved by mobilizing the first method and further encapsulation is done.
In addition, ListenableFuture has several other built-in implementations:
SettableFuture: There is no need to implement a method to calculate the return value, but only a fixed value is needed to return as the return value. You can set the return value or exception information of this Future through the program.
CheckedFuture: This is an inherited from the ListenableFuture interface. It provides the checkedGet() method. This method can throw an exception of the specified type when an exception occurs in Future execution.
RateLimiter is similar to JDK's semaphore. It is used to limit the number of threads to access concurrently to resources. This article introduces the use of RateLimiter.
Code Example
import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;import com.google.common.util.concurrent.FutureCallback;import com.google.common.util.concurrent.Futures;import com.google.common.util.concurrent.ListenableFuture;import com.google.common.util.concurrent.ListeningExecutorService;import com.google.common.util.concurrent.MoreExecutors;import com.google.common.util.concurrent.RateLimiter;public class ListenableFutureDemo {public static void main(String[] args) {testRateLimiter();testListenableFuture();}/** * RateLimiter is similar to the JDK semester Semphore, which is used to limit the number of threads to concurrent access to resources*/public static void testRateLimiter() {ListeningExecutorService executorService = MoreExecutors .listeningDecorator(Executors.newCachedThreadPool());RateLimiter limiter = RateLimiter.create(5.0);// No more than 4 tasks are submitted per second for (int i = 0; i < 10; i++) {limiter.acquire();// Request RateLimiter, exceeding permits will be blocked final ListenableFuture<Integer> listenableFuture = executorService .submit(new Task("is "+ i));}}public static void testListenableFuture() {ListeningExecutorService executorService = MoreExecutors .listeningDecorator(Executors.newCachedThreadPool()); final ListenableFuture<Integer> listenableFuture = executorService .submit(new Task("testListenableFuture"));//Synchronously get the call result try {System.out.println(listenableFuture.get());}catch (InterruptedException e1) {e1.printStackTrace();}catch (ExecutionException e1) {e1.printStackTrace();}//The first way listenableFuture.addListener(new Runnable() {@Override public void run() {try {System.out.println("get listenable future's result " + listenableFuture.get());}catch (InterruptedException e) {e.printStackTrace();}}}, executorService);//The second way Futures.addCallback(listenableFuture, new FutureCallback<Integer>() {@Override public void onSuccess(Integer result) {System.out .println("get listenable future's result with callback " + result);}@Override public void onFailure(Throwable t) {t.printStackTrace();}});}}class Task implements Callable<Integer> {String str;public Task(String str){this.str = str;}@Override public Integer call() throws Exception {System.out.println("call execute.." + str);TimeUnit.SECONDS.sleep(1);return 7;}}Guava version
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>14.0.1</version> </dependency>
Summarize
The above is all about RateLimit - using guava to make interface current limiting code examples. I hope it will be helpful to everyone. Interested friends can continue to refer to other related topics on this site. If there are any shortcomings, please leave a message to point it out. Thank you friends for your support for this site!