經典筆試題:設計一個限流系統


筆試題:

登陸安全的題目,如果你的系統登陸接口在被刷。我們要建立一個防刷系統。

根據登陸ip,30分鍾之內,只能請求30次登陸請求,如果超過這個限制,則整個ip限制登陸請求30分鍾

設計數據結構和實現代碼模擬分布式限流,多線程問題。不允許使用redis等。

 

設計思路:

這道題主要是設計兩個Map,

第一個Map,記錄每個IP及其登錄的時間,題目要求,30分鍾之內只能登錄30次,

所以Map的key為IP,value可以設計一個隊列,隊列長度30,隊列元素為每次的登錄時間。

第二個Map,記錄禁止登錄的IP及禁止開始時間,Map的key為IP,value為時間。

 

實現代碼如下:

/**
 * 限流器實現代碼
 * 單例模式是為了保證一個JVM中只有一個限流器
 */
public class LimitCache {

    private static LimitCache instance;

    // 記錄登錄的ip地址及每次登錄時間
    private static HashMap<String, LinkedList<LocalDateTime>> loginMap = new HashMap<String, LinkedList<LocalDateTime>>();

    // 記錄禁止登錄的ip地址及禁止開始時間
    private static HashMap<String, LocalDateTime> forbiddenMap = new HashMap<String, LocalDateTime>();

    // 私有化構造方法
    private LimitCache() {

    }

    // 單例:雙重檢查模式 (DCL)
    public static synchronized LimitCache getInstance() {
        if (instance == null) {
            synchronized (LimitCache.class) {
                if (instance == null) {
                    instance = new LimitCache();
                }
            }
        }
        return instance;
    }

    public static HashMap<String, LinkedList<LocalDateTime>> getLoginMap() {
        return loginMap;
    }

    public static HashMap<String, LocalDateTime> getForbiddenMap() {
        return forbiddenMap;
    }

}

 

/**
 * 模擬登陸
 *
 */
@RestController
public class LoginController {

    @GetMapping("/login")
    public String login(String ip) {

        String result = "";
        LimitCache limitCache = LimitCache.getInstance();
        LinkedList<LocalDateTime> queue = null;

        // 先判斷ip地址是否禁止登錄
        LocalDateTime forbiddenTime = limitCache.getForbiddenMap().get(ip);
        if (forbiddenTime != null) {
            Long after = ChronoUnit.MINUTES.between(forbiddenTime, LocalDateTime.now());
            if (after <= 30) {
                result = "當前時間=" + LocalDateTime.now() + " 上次禁止登錄時間= " + forbiddenTime + " 距上次被禁時間沒有超過30分鍾";
                return result;
            } else {
                limitCache.getForbiddenMap().clear();
            }
        }

        // 如果是首次登錄,則創建隊列
        if (limitCache.getLoginMap().get(ip) == null) {
            queue = new LinkedList<LocalDateTime>();
        } else {
            queue = limitCache.getLoginMap().get(ip);
        }

        // 登錄次數達到登錄次數上限
        if (queue.size() == 30) {
            // 當前時間和隊列中最早的登錄時間比較 是否小於30分鍾
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime firstLoginTime = queue.poll();
            Long duration = ChronoUnit.MINUTES.between(firstLoginTime, now);
            if (duration <= 30) {
                result = "30分鍾內登錄超過30次,不允許登錄,30分鍾后再登錄";
                // 禁止該IP登錄
                limitCache.getLoginMap().clear();
                limitCache.getForbiddenMap().put(ip, now);
                return result;
            } 
        } 
        
     queue.offer(LocalDateTime.now()); limitCache.getLoginMap().put(ip, queue); result
= ip + " 登錄時間=" + queue.getLast() + " 隊列長度=" + queue.size(); return result; } }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM