【夜話系列】DelayQueue延遲隊列(下):實戰應用與面試精講

?? 本文是DelayQueue系列的下篇,聚焦實戰應用場景和性能優化。通過多個真實案例,帶你掌握DelayQueue在項目中的最佳實踐和性能調優技巧。

?? 系列專欄推薦

  • JAVA集合專欄 【夜話集】
  • JVM知識專欄
  • 數據庫sql理論與實戰
  • 小游戲開發

在這里插入圖片描述

文章目錄

    • 一、DelayQueue實戰應用
      • 1.1 訂單超時自動取消
        • 1.1.1 業務場景分析
        • 1.1.2 實現方案設計
        • 1.1.3 完整代碼示例
        • 1.1.4 注意事項與優化點
      • 1.2 限時優惠券管理
        • 1.2.1 優惠券過期處理
        • 1.2.2 動態失效時間控制
        • 1.2.3 并發安全處理
        • 1.2.4 實現代碼與優化
      • 1.3 緩存過期清理
        • 1.3.1 緩存淘汰策略
        • 1.3.2 延遲清理機制
        • 1.3.3 內存占用優化
        • 1.3.4 示例實現
        • 1.3.5 性能優化建議
      • 1.4 實戰應用總結
    • 二、面試重點解析
      • 2.1 原理相關題目
        • Q1: DelayQueue的核心原理是什么?它是如何保證元素按照延遲時間順序被處理的?
        • Q2: DelayQueue與Timer/TimerTask相比有什么優勢?
        • Q3: DelayQueue是如何實現線程安全的?
      • 2.2 實現細節考點
        • Q1: 如何實現一個自定義的延時任務放入DelayQueue?
        • Q2: DelayQueue的take()方法是如何實現的?為什么它能夠精確地在延遲到期時返回元素?
        • Q3: DelayQueue中的元素可以被更新延遲時間嗎?如何實現?
      • 2.3 應用場景案例
        • Q1: 請設計一個基于DelayQueue的限流器,實現令牌桶算法。
        • Q2: 如何使用DelayQueue實現一個支持定時取消的異步任務系統?
        • Q3: 在分布式系統中,如何結合Redis實現類似DelayQueue的功能?
      • 2.4 性能調優問題
        • Q1: 在高并發場景下,DelayQueue可能面臨哪些性能問題?如何優化?
        • Q2: 如何設計一個支持持久化的DelayQueue,確保系統重啟后任務不丟失?
      • 2.5 面試真題解析
        • 真題1: 如何使用DelayQueue實現一個限流器,要求每個接口每秒最多處理N個請求?
        • 真題2: 在一個電商系統中,如何使用DelayQueue實現秒殺活動的定時開始?
    • 三、思考題
    • 寫在最后

一、DelayQueue實戰應用

1.1 訂單超時自動取消

1.1.1 業務場景分析

在電商系統中,訂單創建后通常需要在一定時間內完成支付,否則系統會自動取消訂單并釋放庫存。這是一個典型的延時任務場景:

  • 訂單創建后,需要設置一個倒計時(通常為15分鐘或30分鐘)
  • 如果在倒計時結束前完成支付,需要取消該延時任務
  • 如果倒計時結束時訂單仍未支付,則自動取消訂單
  • 系統需要支持大量并發訂單的超時管理

傳統實現方式通常采用定時任務掃描數據庫,但這種方式存在以下問題:

  • 數據庫壓力大,特別是訂單量大的場景
  • 實時性不夠,可能出現幾秒甚至幾分鐘的延遲
  • 資源消耗高,需要頻繁掃描數據庫

使用DelayQueue可以很好地解決這些問題,實現內存級的訂單超時管理。

1.1.2 實現方案設計

基于DelayQueue的訂單超時取消方案設計如下:

  1. 創建一個實現Delayed接口的訂單超時任務類
  2. 維護一個全局的DelayQueue,用于管理所有未支付訂單的超時任務
  3. 訂單創建時,向DelayQueue中添加對應的超時任務
  4. 訂單支付成功時,從DelayQueue中移除對應的超時任務
  5. 啟動專門的線程從DelayQueue中獲取到期的任務,執行訂單取消邏輯

這種設計的優勢在于:

  • 內存級處理,性能高
  • 精確的超時控制,無需頻繁掃描數據庫
  • 支持動態取消超時任務
  • 系統重啟后可以通過數據庫中的訂單狀態和創建時間重建延時隊列
1.1.3 完整代碼示例
import java.util.Map;
import java.util.concurrent.*;/*** 基于DelayQueue實現的訂單超時自動取消功能*/
public class OrderTimeoutCancelService {// 訂單超時時間,單位毫秒private final long ORDER_TIMEOUT = 30 * 60 * 1000; // 30分鐘// 延遲隊列,用于處理訂單超時private final DelayQueue<OrderDelayTask> delayQueue = new DelayQueue<>();// 用于存儲訂單與任務的映射關系,便于取消任務private final Map<String, OrderDelayTask> taskMap = new ConcurrentHashMap<>();// 訂單服務,實際業務中通過依賴注入獲取private final OrderService orderService;public OrderTimeoutCancelService(OrderService orderService) {this.orderService = orderService;// 啟動處理線程new Thread(this::processTimeoutOrders).start();}/*** 添加訂單超時任務* @param orderId 訂單ID*/public void addOrderTimeoutTask(String orderId) {// 創建超時任務OrderDelayTask task = new OrderDelayTask(orderId, ORDER_TIMEOUT);// 添加到延遲隊列delayQueue.offer(task);// 保存映射關系taskMap.put(orderId, task);System.out.println("訂單[" + orderId + "]加入超時隊列,將在" + ORDER_TIMEOUT/1000 + "秒后自動取消");}/*** 訂單支付成功,取消超時任務* @param orderId 訂單ID*/public void orderPaid(String orderId) {OrderDelayTask task = taskMap.remove(orderId);if (task != null) {// 從隊列中移除任務(這里利用了equals方法判斷)delayQueue.remove(task);System.out.println("訂單[" + orderId + "]已支付,取消超時任務");}}/*** 處理超時訂單的線程任務*/private void processTimeoutOrders() {System.out.println("訂單超時處理線程已啟動");while (true) {try {// 獲取超時的訂單任務OrderDelayTask task = delayQueue.take();// 從映射中移除taskMap.remove(task.getOrderId());// 執行訂單取消邏輯orderService.cancelOrder(task.getOrderId(), "訂單超時未支付");System.out.println("訂單[" + task.getOrderId() + "]超時未支付,已自動取消");} catch (InterruptedException e) {Thread.currentThread().interrupt();break;} catch (Exception e) {// 處理異常,實際項目中應該有更完善的異常處理System.err.println("處理超時訂單異常:" + e.getMessage());}}}/*** 訂單延遲任務*/static class OrderDelayTask implements Delayed {private final String orderId;private final long expireTime; // 過期時間,單位:毫秒public OrderDelayTask(String orderId, long delayTime) {this.orderId = orderId;this.expireTime = System.currentTimeMillis() + delayTime;}public String getOrderId() {return orderId;}@Overridepublic long getDelay(TimeUnit unit) {return unit.convert(expireTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);}@Overridepublic int compareTo(Delayed o) {return Long.compare(this.expireTime, ((OrderDelayTask) o).expireTime);}@Overridepublic boolean equals(Object obj) {if (this == obj) return true;if (obj == null || getClass() != obj.getClass()) return false;OrderDelayTask that = (OrderDelayTask) obj;return orderId.equals(that.orderId);}@Overridepublic int hashCode() {return orderId.hashCode();}}/*** 模擬訂單服務接口*/interface OrderService {void cancelOrder(String orderId, String reason);}/*** 測試代碼*/public static void main(String[] args) throws InterruptedException {// 模擬訂單服務實現OrderService orderService = (orderId, reason) -> System.out.println("執行訂單[" + orderId + "]取消操作,原因:" + reason);// 創建訂單超時服務OrderTimeoutCancelService service = new OrderTimeoutCancelService(orderService);// 模擬創建3個訂單service.addOrderTimeoutTask("ORDER_001");service.addOrderTimeoutTask("ORDER_002");service.addOrderTimeoutTask("ORDER_003");// 模擬1秒后支付了訂單2Thread.sleep(1000);service.orderPaid("ORDER_002");// 等待所有訂單處理完成Thread.sleep(35000);}
}
1.1.4 注意事項與優化點
  1. 任務去重

    • 重寫了equals和hashCode方法,確保可以根據訂單ID正確移除任務
    • 使用ConcurrentHashMap存儲訂單ID與任務的映射,便于快速查找和取消任務
  2. 異常處理

    • 處理線程中捕獲所有異常,避免因單個任務異常導致整個處理線程終止
    • 實際項目中應該添加更完善的日志記錄和異常處理機制
  3. 系統重啟恢復

    • 系統重啟后,內存中的DelayQueue會丟失所有任務
    • 解決方案:系統啟動時,從數據庫加載所有未支付且未超時的訂單,重新加入DelayQueue
    // 系統啟動時恢復未處理的訂單超時任務
    public void recoverOrderTasks() {List<Order> pendingOrders = orderService.findPendingPaymentOrders();for (Order order : pendingOrders) {// 計算剩余超時時間long createTime = order.getCreateTime().getTime();long now = System.currentTimeMillis();long remainTimeout = createTime + ORDER_TIMEOUT - now;// 如果訂單還未超時,則加入延遲隊列if (remainTimeout > 0) {OrderDelayTask task = new OrderDelayTask(order.getOrderId(), remainTimeout);delayQueue.offer(task);taskMap.put(order.getOrderId(), task);} else {// 已超時但未處理的訂單,直接執行取消邏輯orderService.cancelOrder(order.getOrderId(), "系統重啟,訂單超時未支付");}}System.out.println("成功恢復" + pendingOrders.size() + "個未支付訂單的超時任務");
    }
    
  4. 性能優化

    • 使用線程池替代單個線程處理超時訂單,提高并發處理能力
    • 批量處理超時訂單,減少數據庫操作次數
    • 考慮使用分布式延遲隊列,解決單機容量和可靠性問題

1.2 限時優惠券管理

1.2.1 優惠券過期處理

電商和營銷系統中,限時優惠券是常見的營銷手段。優惠券通常有固定的有效期,過期后需要自動失效。傳統的優惠券過期處理方式有:

  1. 定時任務掃描:定期掃描數據庫,將過期優惠券標記為失效
  2. 使用時判斷:用戶使用優惠券時判斷是否過期
  3. 緩存過期:將優惠券信息存入Redis等緩存,設置過期時間

這些方式各有優缺點,但都不夠實時或資源消耗較大。使用DelayQueue可以實現內存級的優惠券過期管理,既保證實時性,又減少系統資源消耗。

1.2.2 動態失效時間控制

優惠券的一個特點是失效時間可能是動態的:

  • 固定日期失效:如"2023-12-31 23:59:59"
  • 相對時間失效:如"領取后7天內有效"
  • 活動結束失效:如"雙11活動結束后失效"

DelayQueue可以很好地支持這些動態失效時間控制,只需在創建延時任務時計算正確的延遲時間即可。

1.2.3 并發安全處理

優惠券系統面臨的并發場景主要有:

  • 大量用戶同時領取優惠券
  • 用戶使用優惠券的同時,優惠券可能正好過期
  • 系統需要動態調整優惠券的有效期

這些場景需要保證數據一致性和操作的原子性。DelayQueue本身是線程安全的,但與數據庫操作的配合需要特別注意事務和鎖的使用。

1.2.4 實現代碼與優化
import java.util.*;
import java.util.concurrent.*;/*** 基于DelayQueue實現的限時優惠券管理系統*/
public class CouponExpirationManager {// 延遲隊列,用于處理優惠券過期private final DelayQueue<CouponExpireTask> delayQueue = new DelayQueue<>();// 用于存儲優惠券ID與任務的映射關系private final Map<String, CouponExpireTask> taskMap = new ConcurrentHashMap<>();// 優惠券服務,實際業務中通過依賴注入獲取private final CouponService couponService;// 線程池,用于處理過期優惠券private final ExecutorService executorService;public CouponExpirationManager(CouponService couponService) {this.couponService = couponService;// 創建線程池this.executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(),r -> {Thread thread = new Thread(r, "coupon-expiration-thread");thread.setDaemon(true); // 設置為守護線程return thread;});// 啟動處理線程this.executorService.execute(this::processExpiredCoupons);}/*** 添加優惠券過期任務* @param couponId 優惠券ID* @param expireTime 過期時間點(時間戳)*/public void addCouponExpireTask(String couponId, long expireTime) {// 計算延遲時間long delay = expireTime - System.currentTimeMillis();if (delay <= 0) {// 已過期,直接處理couponService.expireCoupon(couponId);return;}// 創建過期任務CouponExpireTask task = new CouponExpireTask(couponId, delay);// 添加到延遲隊列delayQueue.offer(task);// 保存映射關系taskMap.put(couponId, task);System.out.println("優惠券[" + couponId + "]加入過期隊列,將在" + new Date(expireTime) + "過期");}/*** 更新優惠券過期時間* @param couponId 優惠券ID* @param newExpireTime 新的過期時間點(時間戳)*/public void updateCouponExpireTime(String couponId, long newExpireTime) {// 移除舊任務CouponExpireTask oldTask = taskMap.remove(couponId);if (oldTask != null) {delayQueue.remove(oldTask);}// 添加新任務addCouponExpireTask(couponId, newExpireTime);System.out.println("優惠券[" + couponId + "]過期時間已更新為" + new Date(newExpireTime));}/*** 取消優惠券過期任務(優惠券被使用或手動作廢)* @param couponId 優惠券ID*/public void cancelExpireTask(String couponId) {CouponExpireTask task = taskMap.remove(couponId);if (task != null) {delayQueue.remove(task);System.out.println("優惠券[" + couponId + "]過期任務已取消");}}/*** 處理過期優惠券的線程任務*/private void processExpiredCoupons() {System.out.println("優惠券過期處理線程已啟動");while (!Thread.currentThread().isInterrupted()) {try {// 批量處理過期優惠券,提高效率List<CouponExpireTask> expiredTasks = new ArrayList<>();CouponExpireTask task = delayQueue.take(); // 獲取一個過期任務expiredTasks.add(task);// 嘗試一次性獲取多個過期任務delayQueue.drainTo(expiredTasks, 100);// 批量處理過期優惠券List<String> couponIds = new ArrayList<>(expiredTasks.size());for (CouponExpireTask expiredTask : expiredTasks) {String couponId = expiredTask.getCouponId();taskMap.remove(couponId);couponIds.add(couponId);}// 批量更新數據庫couponService.batchExpireCoupons(couponIds);System.out.println("已處理" + couponIds.size() + "張過期優惠券");} catch (InterruptedException e) {Thread.currentThread().interrupt();break;} catch (Exception e) {System.err.println("處理過期優惠券異常:" + e.getMessage());}}}/*** 關閉管理器*/public void shutdown() {executorService.shutdown();try {if (!executorService.awaitTermination(30, TimeUnit.SECONDS)) {executorService.shutdownNow();}} catch (InterruptedException e) {executorService.shutdownNow();Thread.currentThread().interrupt();}}/*** 優惠券過期任務*/static class CouponExpireTask implements Delayed {private final String couponId;private final long expireTime; // 過期時間點,單位:毫秒public CouponExpireTask(String couponId, long delayTime) {this.couponId = couponId;this.expireTime = System.currentTimeMillis() + delayTime;}public String getCouponId() {return couponId;}@Overridepublic long getDelay(TimeUnit unit) {return unit.convert(expireTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);}@Overridepublic int compareTo(Delayed o) {return Long.compare(this.expireTime, ((CouponExpireTask) o).expireTime);}@Overridepublic boolean equals(Object obj) {if (this == obj) return true;if (obj == null || getClass() != obj.getClass()) return false;CouponExpireTask that = (CouponExpireTask) obj;return couponId.equals(that.couponId);}@Overridepublic int hashCode() {return couponId.hashCode();}}/*** 優惠券服務接口*/interface CouponService {void expireCoupon(String couponId);void batchExpireCoupons(List<String> couponIds);}/*** 測試代碼*/public static void main(String[] args) throws InterruptedException {// 模擬優惠券服務實現CouponService couponService = new CouponService() {@Overridepublic void expireCoupon(String couponId) {System.out.println("優惠券[" + couponId + "]已過期");}@Overridepublic void batchExpireCoupons(List<String> couponIds) {System.out.println("批量處理過期優惠券:" + couponIds);}};// 創建優惠券過期管理器CouponExpirationManager manager = new CouponExpirationManager(couponService);// 模擬添加優惠券過期任務Calendar calendar = Calendar.getInstance();// 優惠券1:5秒后過期calendar.add(Calendar.SECOND, 5);manager.addCouponExpireTask("COUPON_001", calendar.getTimeInMillis());// 優惠券2:10秒后過期calendar.add(Calendar.SECOND, 5);manager.addCouponExpireTask("COUPON_002", calendar.getTimeInMillis());// 優惠券3:15秒后過期calendar.add(Calendar.SECOND, 5);manager.addCouponExpireTask("COUPON_003", calendar.getTimeInMillis())

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/76995.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/76995.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/76995.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Redis(筆記)

簡介&#xff1a; 常用數據類型: 常用操作命令&#xff1a; Redis的Java客戶端&#xff1a; 操作字符串類型的數據&#xff1a; 操作Hash類型的數據&#xff1a; 操作列表類型的數據&#xff1a; 操作集合類型的數據&#xff1a; 操作有序集合類型數據&#xff1a; 通用命令…

PhotoShop學習05

1.選區基礎知識 選區&#xff0c;就是選定一些區域&#xff0c;我們對圖片的更改只在選區內生效&#xff0c;這樣可以精細調整圖片的部分而不會影響整體。它的快捷鍵是M。 我們用點擊鼠標后滑動就會出現虛線框&#xff0c;虛線框內的就是我們選定的區域。這時我們再滑動就會創…

使用Redission實現分布式鎖

分布式鎖在分布式系統中非常重要&#xff0c;主要用于解決多個進程/服務并發訪問共享資源時的數據一致性問題。在日常開發中常用于&#xff1a; 1. 防止重復操作&#xff08;冪等性控制&#xff09; 場景&#xff1a;用戶重復提交訂單、重復支付、重復點擊等。 示例&#xff1…

VScode 畫時序圖(FPGA)

1、先安裝插件&#xff1a; 2、然后就可以編寫一個.js文件&#xff0c;如下&#xff1a; {signal: [{name: clk, wave: p.......|..},{name: rstn, wave: 01......|..},{name: din_vld, wave: 0.1.0...|..},{name: din, wave: "x.x...|..", data: ["D0", …

嵌入式學習筆記——I2C

IIC協議詳解 一、IIC協議簡介二、IIC總線結構圖三、IIC通信流程詳解1. 空閑狀態 : 雙高空閑2. 起始信號&#xff08;START&#xff09;: 時高數下開始3. 停止信號&#xff08;STOP&#xff09;: 時高數上結束4. 數據傳輸格式 : 時高數穩&#xff0c;時低數變5. 應答信號 四、寫…

Apifox Helper 與 Swagger3 區別

核心定位差異 Apifox Helper 定位&#xff1a;基于 IDEA 的代碼注釋解析工具&#xff0c;與 Apifox 平臺深度集成&#xff0c;實現文檔自動生成接口管理測試協作的一體化流程。 特點&#xff1a; 通過解析 Javadoc、KDoc 等注釋生成文檔&#xff0c;代碼零侵入&#xff08;無…

單片機實現多線程的方法匯總

在單片機上實現“多線程”的方法有幾種&#xff0c;下面按照從簡單到復雜、從輕量到系統性來列出常見的方案&#xff1a; &#x1f9f5; 一、偽多線程&#xff08;最輕量&#xff09; 方法&#xff1a;主循環 狀態機 / 定時器輪詢 主循環中輪流調用各個任務的處理函數&#x…

網絡:華為數通HCIA學習:靜態路由基礎

文章目錄 前言靜態路由基礎靜態路由應用場景 靜態路由配置靜態路由在串行網絡的配置靜態路由在以太網中的配置 負載分擔配置驗證 路由備份&#xff08;浮動靜態路由&#xff09;配置驗證 缺省路由配置驗證 總結 華為HCIA 基礎實驗&#xff0d;靜態路由 & eNSP靜態路由 基礎…

[項目總結] 在線OJ刷題系統項目技術應用(下)

&#x1f338;個人主頁:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;?熱門專欄: &#x1f9ca; Java基本語法(97平均質量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection與…

Qt音頻輸出:QAudioOutput詳解與示例

1. 簡介 QAudioOutput是Qt多媒體框架中的一個關鍵類&#xff0c;它提供了將PCM&#xff08;脈沖編碼調制&#xff09;原始音頻數據發送到音頻輸出設備的接口。作為Qt多媒體組件的一部分&#xff0c;QAudioOutput允許開發者在應用程序中實現音頻播放功能&#xff0c;支持多種音…

【計算機網絡】Linux配置SNAT/DNAT策略

什么是NAT&#xff1f; NAT 全稱是 Network Address Translation&#xff08;網絡地址轉換&#xff09;&#xff0c;是一個用來在多個設備共享一個公網 IP上網的技術。 NAT 的核心作用&#xff1a;將一個網絡中的私有 IP 地址&#xff0c;轉換為公網 IP 地址&#xff0c;從而…

Redis淘汰策略詳解!

目錄 一、為什么需要淘汰策略&#xff1f; &#x1f914;二、Redis 的淘汰策略詳解 &#x1f447;三、如何選擇合適的淘汰策略&#xff1f; &#x1f914;???四、如何切換 Redis 的淘汰策略&#xff1f; ??&#x1f527;五、總結 &#x1f389; &#x1f31f;我的其他文章…

存儲基石:深度解讀Linux磁盤管理機制與文件系統實戰

Linux系列 文章目錄 Linux系列前言一、磁盤1.1 初識磁盤1.2 磁盤的物理結構1.3 磁盤的存儲結構1.4 磁盤的邏輯結構 二、文件系統2.1 系統對磁盤的管理2.2 文件在磁盤中的操作 前言 Linux 文件系統是操作系統中用于管理和組織存儲設備&#xff08;如硬盤、SSD、USB 等&#xff…

本節課課堂總結

匿名子類&#xff1a; 說明 和 Java 一樣&#xff0c;可以通過包含帶有定義或重寫的代碼塊的方式創建一個匿名的子類。 單例對象&#xff08;伴生對象&#xff09; Scala語言是完全面向對象的語言&#xff0c;所以并沒有靜態的操作&#xff08;即在Scala中沒有靜態的概念&a…

I2C、SPI、UART、CAN 通信協議詳解

一、協議基本特性對比 特性ICSPIUARTCAN通信類型同步、半雙工同步、全雙工異步、全雙工異步、多主多從信號線SDA&#xff08;數據&#xff09;、SCL&#xff08;時鐘&#xff09;MOSI、MISO、SCK、SS&#xff08;片選&#xff09;TX&#xff08;發送&#xff09;、RX&#xff…

【diffusers 進階(十五)】dataset 工具,Parquet和Arrow 數據文件格式,load dataset 方法

系列文章目錄 【diffusers 極速入門&#xff08;一&#xff09;】pipeline 實際調用的是什么&#xff1f; call 方法!【diffusers 極速入門&#xff08;二&#xff09;】如何得到擴散去噪的中間結果&#xff1f;Pipeline callbacks 管道回調函數【diffusers極速入門&#xff0…

第十三章:持久化存儲_《鳳凰架構:構建可靠的大型分布式系統》

第十三章 持久化存儲 一、Kubernetes存儲設計核心概念 &#xff08;1&#xff09;存儲抽象模型 PersistentVolume (PV)&#xff1a;集群級別的存儲資源抽象&#xff08;如NFS卷/云存儲盤&#xff09;PersistentVolumeClaim (PVC)&#xff1a;用戶對存儲資源的聲明請求&#…

以太網安全

前言&#xff1a; 端口隔離可實現同一VLAN內端口之間的隔離。用戶只需要將端口加入到隔離組中&#xff0c;就可以實現隔離組內端口之間的二層數據的隔離端口安全是一種在交換機接入層實施的安全機制&#xff0c;旨在通過控制端口的MAC地址學習行為&#xff0c;確保僅授權設備能…

跨域問題前端解決

由于瀏覽器的同源策略&#xff0c;前后端分離的項目&#xff0c;調試的時候總是會遇到跨域的問題&#xff0c;這里通過修改前端代碼解決跨域問題。 首先先查看前端代碼的根目錄下&#xff0c;有沒有vue.config.js文件, 若有&#xff0c;使用方法1&#xff0c;若沒有此文件&…

Elasticsearch 報錯index_closed_exception

index_closed_exception 是 Elasticsearch 中的一個異常類型&#xff0c;它通常發生在嘗試對一個已經被關閉&#xff08;closed&#xff09;的索引執行搜索、寫入或其他操作時。在 Elasticsearch 中&#xff0c;索引是用來存儲和檢索數據的邏輯命名空間&#xff0c;可以將其類比…