成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

100萬的并發(fā),如何設(shè)計(jì)一個(gè)商品搜索系統(tǒng)?

開發(fā) 架構(gòu)
假設(shè)場景:某電商平臺大促期間,需支撐每秒100萬次的商品搜索請求,要求響應(yīng)時(shí)間≤200ms,同時(shí)應(yīng)對商品數(shù)據(jù)量超10億條。假設(shè)給你來做系統(tǒng)設(shè)計(jì),怎么做呢?

前言

今天我們來看一道比較有深度的面試題:百萬并發(fā)下,商品搜索系統(tǒng),你如何設(shè)計(jì)呢?

假設(shè)場景:某電商平臺大促期間,需支撐每秒100萬次的商品搜索請求,要求響應(yīng)時(shí)間≤200ms,同時(shí)應(yīng)對商品數(shù)據(jù)量超10億條。假設(shè)給你來做系統(tǒng)設(shè)計(jì),怎么做呢?

如果是我來回答面試官這道題的話,我會(huì)按照這些思路來跟面試官闡述:

  • 為什么不能用MySQL的llike?
  • 總體架構(gòu)設(shè)計(jì)
  • 核心關(guān)鍵設(shè)計(jì)

1.為什么不能用mysql的like?

我們每次提到關(guān)鍵詞搜索,大家很容易就想到數(shù)據(jù)庫的like,比如:

SELECT * FROM products WHERE title LIKE '%智能手機(jī)%' LIMIT 10;

但是,顯然商品數(shù)據(jù)量超10億條,搜索不能用like。

  • LIKE '%keyword%' 無法利用索引,觸發(fā)全表掃描。10億數(shù)據(jù)時(shí)單次查詢可能耗時(shí)數(shù)秒。
  • 不支持分詞搜索(如"手機(jī)殼"無法拆分為"手機(jī)"和"殼"單獨(dú)匹配)
  • 分庫分表后跨庫LIKE查詢復(fù)雜度指數(shù)級上升

可以使用Elasticsearch ,但是我們是做系統(tǒng)設(shè)計(jì),肯定不能直接回答面試官,說,用Elasticsearch呀,而是按照系統(tǒng)設(shè)計(jì)的思想(高可用 + 可擴(kuò)展),說一整個(gè)鏈路。

2. 總體架構(gòu)設(shè)計(jì)

  • 用戶層(前端 + CDN)
  • 接入層(Nginx )
  • 服務(wù)層(Search Gateway )
  • 檢索層(搜索引擎,如 Elasticsearch)
  • 數(shù)據(jù)層(商品數(shù)據(jù)服務(wù) / DB / 緩存)

圖片圖片

2.1 用戶層(前端 + CDN)

  • 請求分發(fā):通過CDN加速靜態(tài)資源(圖片/JS/CSS)
  • 瀏覽器緩存:利用LocalStorage緩存高頻搜索關(guān)鍵詞
  • 請求合并:合并相似搜索請求(如防抖機(jī)制)
// 前端防抖示例(減少無效請求)
let searchTimer;
function handleSearch(keyword) {
    clearTimeout(searchTimer);
    searchTimer = setTimeout(() => {
        fetch(`/api/search?q=${encodeURIComponent(keyword)}`);
    }, 300); // 300ms防抖
}

2.2 接入層(Nginx)

  • 流量管控:限流、熔斷、鑒權(quán)
  • 負(fù)載均衡:輪詢/一致性哈希分發(fā)請求
  • 協(xié)議轉(zhuǎn)換:HTTP/2 → HTTP/1.1內(nèi)部通信

Nginx 關(guān)鍵配置

# 限流配置(每秒1000請求/ip)
limit_req_zone $binary_remote_addr znotallow=search_limit:10m rate=1000r/s;

location /api/search {
    limit_req znotallow=search_limit burst=200;
    proxy_pass http://search_cluster;
    
    # 緩存熱門請求結(jié)果(5秒)
    proxy_cache search_cache;
    proxy_cache_valid 200 5s;
}

2.3 服務(wù)層(Search Gateway)

  • 業(yè)務(wù)邏輯:請求參數(shù)校驗(yàn)、結(jié)果格式化
  • 多級緩存:本地緩存 → Redis → Elasticsearch
  • 降級策略:超時(shí)返回兜底數(shù)據(jù)
// 搜索網(wǎng)關(guān)偽代碼
public class SearchGateway {
    @Cacheable(value = "localCache", key = "#keyword")
    public List<Product> search(String keyword) {
        // 1. 檢查Redis緩存
        String redisKey = "search:" + keyword.hashCode();
        List<Product> cached = redis.get(redisKey);
        if (cached != null) return cached;
        
        // 2. 查詢Elasticsearch
        List<Product> result = elasticsearch.search(buildQuery(keyword));
        
        // 3. 異步寫入緩存
        executor.submit(() -> {
            redis.setex(redisKey, 30, result); // 緩存30秒
        });
        
        return result;
    }
}

2.4 檢索層(Elasticsearch)

  • 索引構(gòu)建:商品標(biāo)題/類目/屬性倒排索引
  • 分布式查詢:分片并行計(jì)算
  • 相關(guān)性排序:BM25算法優(yōu)化

索引設(shè)計(jì)demo:

PUT /products
{
"settings": {
    "number_of_shards": 40,
    "number_of_replicas": 1,
    "refresh_interval": "30s" // 降低寫入實(shí)時(shí)性要求
  },
"mappings": {
    "properties": {
      "title": { "type": "text", "analyzer": "ik_max_word" },
      "price": { "type": "double" },
      "sales": { "type": "integer" }
    }
  }
}

2.5 數(shù)據(jù)層(DB + 緩存)

  • 持久化存儲:MySQL分庫分表
  • 數(shù)據(jù)同步:Binlog → Canal → Elasticsearch
  • 冷熱分離:Redis緩存熱數(shù)據(jù),HBase存歷史數(shù)據(jù)

分庫分表demo

-- 按商品ID分64個(gè)庫,每個(gè)庫分256表
CREATE TABLE products_%02d.t_product_%03d (
    id BIGINT PRIMARY KEY,
    title VARCHAR(255),
    price DECIMAL(10,2)
) ENGINE=InnoDB;
-- 分片路由算法:hash(product_id) % 64 → 分庫
-- hash(product_id) / 64 % 256 → 分表

3. 核心關(guān)鍵設(shè)計(jì)

3.1 分片與容量設(shè)計(jì)(水平擴(kuò)展)

  • 使用 Elasticsearch,每個(gè)索引進(jìn)行合理分片(Sharding)

每個(gè)分片大小控制在 20-50 GB,避免 OOM 和延遲增加

按業(yè)務(wù)維度(如商品類目、國家)分索引或路由分片

  • 分片副本(Replica)數(shù)設(shè)置,提升可用性

3.2 深度分頁性能優(yōu)化

我們在使用mysql做查詢的時(shí)候,會(huì)遇到深分頁的問題,比如回表十萬次

圖片圖片

我們可以用標(biāo)簽記錄法,來解決深分頁問題

其實(shí)Elasticsearch 也存在深分頁的問題,當(dāng)用戶翻頁到幾百頁時(shí),ES 會(huì)做全量掃描,性能陡降。

  • 避免傳統(tǒng) from + size 深分頁
  • Search After(推薦):基于上一頁最后一個(gè) sort_value 做游標(biāo)分頁。(類似標(biāo)簽記錄法思想)
  • Scroll API:適用于數(shù)據(jù)導(dǎo)出,不推薦用戶查詢
  • 或業(yè)務(wù)限制分頁范圍(如最多展示 100 頁)

3.3 避免緩存穿透設(shè)計(jì)

跟大家一起復(fù)習(xí)一下,什么是緩存穿透?

指查詢一個(gè)一定不存在的數(shù)據(jù),由于緩存是不命中時(shí)需要從數(shù)據(jù)庫查詢,查不到數(shù)據(jù)則不寫入緩存,這將導(dǎo)致這個(gè)不存在的數(shù)據(jù)每次請求都要到數(shù)據(jù)庫去查詢,進(jìn)而給數(shù)據(jù)庫帶來壓力。

在百萬并發(fā)商品搜索系統(tǒng)時(shí),我們要避免這個(gè)問題,可以用布隆過濾器,簡單流程圖如下:

圖片圖片

核心業(yè)務(wù)邏輯(代碼簡單demo):

@Service
public class SearchService {
    // 布隆過濾器(存儲所有有效關(guān)鍵詞)
    @Autowired
    private BloomFilter<String> searchBloomFilter;

    // Redis緩存操作
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public SearchResult search(String keyword) {
        // Step 1: 布隆過濾器校驗(yàn)
        if (!searchBloomFilter.mightContain(normalizeKeyword(keyword))) {
            return SearchResult.EMPTY;
        }

        // Step 2: 查詢緩存
        String cacheKey = "search:" + keyword.hashCode();
        SearchResult cached = (SearchResult) redisTemplate.opsForValue().get(cacheKey);
        if (cached != null) return cached;

        // Step 3: 查詢Elasticsearch
        SearchResult result = elasticsearchClient.search(buildQuery(keyword));

        // Step 4: 更新緩存
        if (result.isEmpty()) {
            redisTemplate.opsForValue().set(cacheKey, SearchResult.EMPTY, 30, TimeUnit.SECONDS);
        } else {
            redisTemplate.opsForValue().set(cacheKey, result, 5, TimeUnit.MINUTES);
        }

        return result;
    }

    // 關(guān)鍵詞標(biāo)準(zhǔn)化處理(如去空格、轉(zhuǎn)小寫)
    private String normalizeKeyword(String keyword) {
        return keyword.trim().toLowerCase();
    }
}
這里有個(gè)點(diǎn)可能要注意一下哈,布隆過濾器需要初始化一下:
// 初始化所有有效關(guān)鍵詞到布隆過濾器
@PostConstruct
public void initBloomFilter() {
    List<String> allKeywords = productDao.getAllSearchKeywords(); // 獲取所有商品標(biāo)題/標(biāo)簽
    allKeywords.stream()
               .map(this::normalizeKeyword)
               .forEach(searchBloomFilter::put);
}

// 動(dòng)態(tài)更新(新增商品時(shí))
public void addProduct(Product product) {
    // ... 其他業(yè)務(wù)邏輯
    searchBloomFilter.put(normalizeKeyword(product.getTitle()));
    product.getTags().forEach(tag -> 
        searchBloomFilter.put(normalizeKeyword(tag))
    );
}

3.4 GC調(diào)優(yōu)

既然是百萬并發(fā)的系統(tǒng)設(shè)計(jì),少不了GC調(diào)優(yōu)。

盡量降低 Full GC 頻率:

  • 使用 G1 或 ZGC
  • 調(diào)大堆內(nèi)存(視機(jī)器資源)
  • 避免頻繁創(chuàng)建臨時(shí)對象,使用對象池(如 Query 對象)

在上線前,我們要進(jìn)行壓力測試,然后調(diào)出最優(yōu)最優(yōu)JVM參數(shù)。JVM 最優(yōu)參數(shù)配置不是一成不變的,根據(jù)實(shí)際壓測,得到的

壓力測試可以用loadrunner或者jemeter,進(jìn)行高并發(fā)模擬測試。

JVM 參數(shù)配置demo

# elasticsearch/jvm.options

# 基礎(chǔ)配置
-Xms31g
-Xmx31g
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200

# G1調(diào)優(yōu)參數(shù)
-XX:InitiatingHeapOccupancyPercent=35
-XX:G1ReservePercent=25
-XX:G1HeapReginotallow=4m

# 內(nèi)存鎖防止Swap
-XX:+AlwaysPreTouch
-XX:+DisableExplicitGC

3.5 災(zāi)備與高可用設(shè)計(jì)

高并發(fā)系統(tǒng),少不了容災(zāi)和高可用的設(shè)計(jì)要點(diǎn),可以采取以下幾種方式:
  • 多 AZ 部署(分布在不同機(jī)房 / 可用區(qū))
  • Elasticsearch 設(shè)置跨機(jī)房副本(replica + shard allocation awareness)
  • 服務(wù)注冊中心(如 Nacos)與服務(wù)熔斷、降級策略配合
  • 主從切換、故障自動(dòng)轉(zhuǎn)移(Failover)

圖片圖片


責(zé)任編輯:武曉燕 來源: 撿田螺的小男孩
相關(guān)推薦

2023-09-08 08:10:48

2023-09-08 08:22:30

2019-08-01 08:36:51

緩存系統(tǒng)并發(fā)

2025-06-23 08:23:04

2021-04-28 08:52:22

高并發(fā)架構(gòu)設(shè)高并發(fā)系統(tǒng)

2019-07-31 07:36:12

架構(gòu)運(yùn)維技術(shù)

2018-09-18 09:38:11

RPC遠(yuǎn)程調(diào)用網(wǎng)絡(luò)通信

2025-06-04 03:15:00

高并發(fā)短鏈系統(tǒng)

2024-04-24 10:38:22

2024-11-20 13:18:21

2024-08-27 12:49:20

2020-09-02 07:22:17

JavaScript插件框架

2013-08-14 10:48:23

實(shí)時(shí)計(jì)算流計(jì)算

2019-08-12 10:45:54

Flutter框架Native

2015-07-28 14:35:40

2015-11-13 10:25:04

京東商品搜索架構(gòu)

2020-07-27 07:53:36

高并發(fā)流量系統(tǒng)

2025-04-29 02:00:00

高并發(fā)系統(tǒng)場景

2013-07-01 11:01:22

API設(shè)計(jì)API

2022-07-18 08:02:16

秒殺系統(tǒng)后端
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 亚洲一区二区在线视频 | 久久精品网| 99视频在线免费观看 | 亚洲一区在线日韩在线深爱 | 亚洲影音 | 国产精品91久久久久久 | 欧美一区二区三区四区视频 | 一区二区三区免费网站 | 午夜视频在线观看网站 | 亚洲精品一区中文字幕乱码 | 欧美成人一区二免费视频软件 | 羞羞的视频免费观看 | 欧美精品在线一区二区三区 | 日韩aⅴ片 | 国产成人精品久久二区二区91 | 波多野结衣一区二区三区在线观看 | 国产成人精品一区二区三区四区 | 人人艹人人爽 | 在线观看黄色 | 99亚洲精品| 国产中文| 色狠狠一区| 一级全黄少妇性色生活免费看 | 激情毛片 | a级大片免费观看 | 精品在线一区 | 成人在线视频免费播放 | 精品亚洲国产成av人片传媒 | 免费人成在线观看网站 | 日韩av一区在线观看 | 欧美国产精品 | 久久久久99 | 日韩久久久久久 | 狠狠av| 成人影院在线视频 | 欧美一级在线观看 | 欧美不卡 | 国产成人av在线 | 美女二区| 国产清纯白嫩初高生在线播放视频 | 亚洲国产一区二区视频 |