java併發編程筆記(十一)——高併發處理思路和手段

java併發編程筆記(十一)——高併發處理思路和手段

擴容

  • 垂直擴容(縱向擴展):提升系統部件能力
  • 水平擴容(橫向擴容):增長更多系統成員來實現

緩存

緩存特徵

命中率:命中數/(命中數+沒有命中數)java

1、影響因素算法

  • 業務場景和業務需求
  • 緩存的設計(粒度和策略)
  • 緩存的容量和基礎設施

2、緩存分類和應用場景spring

  • 本地緩存:編程實現(成員變量,局部變量,靜態變量)、Guava Cache
  • 分佈式緩存:Memcache、Redis

3、經常使用組件數據庫

  • Guava Cacheapache

    public class GuavaCacheExample1 {
    
        public static void main(String[] args) {
    
            LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
                    .maximumSize(10) // 最多存放10個數據
                    .expireAfterWrite(10, TimeUnit.SECONDS) // 緩存10秒
                    .recordStats() // 開啓記錄狀態數據功能
                    .build(new CacheLoader<String, Integer>() {
                        @Override
                        public Integer load(String key) throws Exception {
                            return -1;
                        }
                    });
    
            log.info("{}", cache.getIfPresent("key1")); // null
            cache.put("key1", 1);
            log.info("{}", cache.getIfPresent("key1")); // 1
            cache.invalidate("key1");
            log.info("{}", cache.getIfPresent("key1")); // null
    
            try {
                log.info("{}", cache.get("key2")); // -1
                cache.put("key2", 2);
                log.info("{}", cache.get("key2")); // 2
    
                log.info("{}", cache.size()); // 1
    
                for (int i = 3; i < 13; i++) {
                    cache.put("key" + i, i);
                }
                log.info("{}", cache.size()); // 10
    
                log.info("{}", cache.getIfPresent("key2")); // null
    
                Thread.sleep(11000);
    
                log.info("{}", cache.get("key5")); // -1
    
                log.info("{},{}", cache.stats().hitCount(), cache.stats().missCount());
    
                log.info("{},{}", cache.stats().hitRate(), cache.stats().missRate());
            } catch (Exception e) {
                log.error("cache exception", e);
            }
        }
    }
  • Memcache編程

  • Redis緩存

最大元素(空間):緩存大小 服務器

清空策略:FIFO、LFO、LRU、過時時間,隨機等網絡

FIFO: 先進先出策略mybatis

LFO:最少使用策略

LRU:最近最少使用策略

高併發場景下緩存常見問題

緩存一致性

形成這種問題的場景:

  • 更新數據庫成功--更新緩存失敗--數據不一致
  • 更新緩存成功--更新數據庫失敗--數據不一致
  • 更新數據庫成功--淘汰緩存失敗--數據不一致
  • 淘汰緩存成功--更新數據庫失敗--查詢緩存miss

緩存併發問題

同時大量請求訪問緩存未命中,而後大量請求同時訪問數據庫形成數據庫壓力增大,解決辦法是加鎖,避免同時執行

緩存穿透問題

某個查詢結果爲空,致使緩存爲存儲,所以大量請求會去查詢數據庫,形成對數據庫的壓力大增

解決辦法:

一、緩存空對象,緩存時間要短,適合命中率不高,可是須要頻繁修改的數據

二、進行單獨過濾處理,對全部可能結果爲空的請求進行統一存放,而且對請求進行攔截,避免請求到數據庫對數據庫形成大量壓力

緩存雪崩現象

致使緣由:緩存併發,緩存穿透等

解決辦法:過時時間設置隨機數,避免同時失效10

消息隊列

特性

  • 業務無關:只作消息分發
  • FIFO:先投遞先到達
  • 容災:節點的動態增長和消息的持久化
  • 性能:吞吐量提高,系統內部通訊效率提升

爲何須要消息隊列

  • 【生產和消費】的速度或穩定性等因素不一致

消息隊列的好處

  • 業務解耦
  • 最終一致性
  • 廣播
  • 錯峯和流控

舉例

  • Kafka
  • RabbitMQ

應用拆分

拆分原則

  • 業務優先
  • 按部就班
  • 兼顧技術:重構、分層
  • 可靠測試

須要考慮的問題

  • 應用之間的通訊:RPC(dubbo等)、消息隊列
  • 應用之間數據數據庫設計:每一個應用都有獨立的數據庫
  • 避免事務操做跨應用

通訊工具

  • dubbo
  • springCloud

應用限流

經常使用限流算法

  • 計數器法

  • 滑動窗口法

  • 漏桶算法

  • 令牌桶算法(Guava RateLimit)

    @Slf4j
    public class RateLimiterExample1 {
    
        private static RateLimiter rateLimiter = RateLimiter.create(5);
    
        public static void main(String[] args) throws Exception {
    
            for (int index = 0; index < 100; index++) {
                if (rateLimiter.tryAcquire(190, TimeUnit.MILLISECONDS)) {
                    handle(index);
                }
            }
        }
    
        private static void handle(int i) {
           log.info("{}", i);
        }
    }
    @Slf4j
    public class RateLimiterExample2 {
    
        private static RateLimiter rateLimiter = RateLimiter.create(5);
    
        public static void main(String[] args) throws Exception {
    
            for (int index = 0; index < 100; index++) {
                rateLimiter.acquire();
                handle(index);
            }
        }
    
        private static void handle(int i) {
           log.info("{}", i);
        }
    }

    Guava RateLimiter是單機版的限流

    若是是分佈式能夠採用 分佈式限流:

    能夠採用Redis做爲中間組件,使用Redis的incrby key num 方法

服務降級與服務熔斷

服務降級

  • 自動降級:超時、失敗次數、故障、限流
  • 人工降級:秒殺、雙11大促

服務熔斷

總結

共性:目的、最終表現、粒度、自治

區別:

  • 觸發緣由、管理目標層次、實現方式

服務降級要考慮的問題

  • 核心服務、非核心服務
  • 是否支持降級、降級策略
  • 業務放通場景,策略

Hystrix

  • 在經過第三方客戶端訪問(一般是經過網絡)依賴服務出現高延遲或者失敗時,爲系統提供保護和控制。
  • 在分佈式系統中防止級聯失敗
  • 快速失敗(fail fast)同時能快速恢復
  • 提供失敗回退(Fallback)和優雅的服務降級機制
  • 提供近實時的監控、報警和運維控制手段

數據庫切庫、分庫、分表

數據庫瓶頸

  • 單個庫數據量太大(1T~2T):多個庫
  • 單個數據庫服務器壓力過大、讀寫瓶頸:多個庫
  • 單個表數據量過大:分表

數據庫切庫

  • 切庫的基礎及實際運用:讀寫分離
  • 自定義註解完成數據庫切庫-代碼實現

  • 支持多數據源、分庫
  • 數據庫支持多個數據源-代碼實現

數據庫分表

  • 何時考慮分表
  • 橫向(水平)分表和縱向(垂直)分表
  • 數據庫分表:mybatis分表插件shardbatis2.0

高可用的一些手段

  • 任務調度系統分佈式:elastic-job+zookeeper
  • 主備切換:apache curator + zookeeper分佈式鎖實現
  • 監控報警機制
相關文章
相關標籤/搜索