第十二章 Net 5.0 快速開發框架 YC.Boilerplate --千萬級資料處理解決方案

linbin524發表於2021-10-10

線上文件:http://doc.yc-l.com/#/README
線上演示地址:http://yc.yc-l.com/#/login
原始碼github:https://github.com/linbin524/yc.boilerplate
原始碼gitee:https://gitee.com/linxuanming/yc.boilerplate

視訊教程:
元磁之力框架開源初心和框架設計介紹(上): https://www.bilibili.com/video/BV1VM4y1G7hC/
元磁之力框架開源初心和框架設計介紹(下): https://www.bilibili.com/video/BV15h411s7w6/
元磁之力框架資料庫表和程式碼生成使用教程實戰: https://www.bilibili.com/video/BV1oM4y137D5/

QQ群:1060819005

後續:關於框架demo和細節技巧,會在QQ群中釋出,就不撰文說明。

大資料套件 ElasticSearch

簡介

為了提升YC.Boilerlate 在大資料量的處理能力,引入ES元件,封裝對應的模組、實現租戶拆分、倉儲、叢集、大資料上億級別以上資料的檢索、統計、分析,並提供千萬級別分詞搜尋等演示示例。

ES基礎介紹

Elasticsearch 是一個分散式、RESTful 風格的搜尋和資料分析引擎,是PB級別大資料解決方案元件之一。
Elasticsearch是基於Lucense的搜尋伺服器,,基於RESTful web介面。Elasticsearch是Java語言開發的,並作為Apache許可條款下的開放原始碼釋出,是一種流行的企業級搜尋引擎。Elasticsearch用於雲端計算中,能夠達到實時搜尋,穩定,可靠,快速,安裝使用方便。

ES解決什麼問題

對海量資料進行近實時的處理

ES自動可以將海量資料分散到多臺伺服器上去儲存和檢索,通過內建搜尋引擎、分詞、實現
千萬級別資料秒級查詢、統計、分析等,相對傳統關係型資料庫的模糊查詢在速度有著質的飛躍。

ES 適用場景

  • 維基百科,類似百度百科,牙膏,牙膏的維基百科,全文檢索,高亮,搜尋推薦

  • The Guardian(國外新聞網站),類似搜狐新聞,使用者行為日誌(點選,瀏覽,收藏,評論)+社交網路資料(對某某新聞的相關看法),資料分析,給到每篇新聞文章的作者,讓他知道他的文章的公眾反饋(好,壞,熱門,垃圾,鄙視,崇拜)

  • Stack Overflow(國外的程式異常討論論壇),IT問題,程式的報錯,提交上去,有人會跟你討論和回答,全文檢索,搜尋相關問題和答案,程式報錯了,就會將報錯資訊貼上到裡面去,搜尋有沒有對應的答案

  • GitHub(開原始碼管理),搜尋上千億行程式碼

  • 電商網站,檢索商品

  • 日誌資料分析,logstash採集日誌,ES進行復雜的資料分析(ELK技術,elasticsearch+logstash+kibana)

  • 商品價格監控網站,使用者設定某商品的價格閾值,當低於該閾值的時候,傳送通知訊息給使用者,比如說訂閱牙膏的監控,如果高露潔牙膏的家庭套裝低於50塊錢,就通知我,我就去買

  • BI系統,商業智慧,Business Intelligence。比如說有個大型商場集團,BI,分析一下某某區域最近3年的使用者消費金額的趨勢以及使用者群體的組成構成,產出相關的數張報表,**區,最近3年,每年消費金額呈現100%的增長,而且使用者群體85%是高階白領,開一個新商場。ES執行資料分析和挖掘,Kibana進行資料視覺化國內

  • 國內:站內搜尋(電商,招聘,門戶,等等),IT系統搜尋(OA,CRM,ERP,等等),資料分析(ES熱門的一個使用場景)

ES 常用組合

  • ELK :Elasticsearch是與名為Logstash的資料收集和日誌解析引擎以及名為Kibana的分析和視覺化平臺一起開發的。這三個產品被設計成一個整合解決方案。
    Elasticsearch可以用於搜尋各種文件。它提供可擴充套件的搜尋,具有接近實時的搜尋,並支援多租戶。Elasticsearch是分散式的,這意味著索引可以被分成分片,每個分片可以有0個或多個副本。每個節點託管一個或多個分片,並充當協調器將操作委託給正確的分片。再平衡和路由是自動完成的。相關資料通常儲存在同一個索引中,該索引由一個或多個主分片和零個或多個複製分片組成。一旦建立了索引,就不能更改主分片的數量。

  • 阿里巴巴開發的canal:基於Mysql的binlog日誌訂閱:binlog日誌是Mysql用來記錄資料實時的變化。這裡主要的是binlog同步元件,目前實現的有國內的。
    github地址:https://github.com/alibaba/canal

  • go-mysql-elasticsearch:go-mysql-elasticsearch是一款使用go語言開發的同步資料到ES的工具。 go-mysql-elasticsearch也是基於Mysql的binlog訂閱,也可以使用使用mysqldump的方式。目前還不支援ES6.x及以上的版本,也不支援mysql8.x版本,同時該專案目前還不夠穩定,也在開發中。
    專案github地址:https://github.com/siddontang/go-mysql-elasticsearch

ES 和常規關係型資料庫差異

ES中有幾個基本概念:索引(index)、型別(type)、文件(document)、對映(mapping)等。我們將這幾個概念與傳統的關係型資料庫中的庫、表、行、列等概念進行對比,如下表:

常規問題

  • 記憶體:es 的預設配置在常規伺服器上大部分都有記憶體使用率的問題,需要根據實際情況合理調優。

  • 版本:ES 每個版本配套元件有極強耦合,無法做到各個版本相容,所以jdk、以及其他元件需要指定適配。

  • 分詞:es除了內建standard分詞,還可以其他分片語件,對中文支援比較好的有:es-ik。

  • 分片(shard): 因為 ES 是個分散式的搜尋引擎, 所以索引通常都會分解成不同部分, 而這些分佈在不同節點的資料就是分片. ES自動管理和組織分片, 並在必要的時候對分片資料進行再平衡分配, 所以使用者基本上不用擔心分片的處理細節.

  • 副本(replica): ES 預設為一個索引建立 5 個主分片, 並分別為其建立一個副本分片. 也就是說每個索引都由 5 個主分片成本, 而每個主分片都相應的有一個 copy。對於分散式搜尋引擎來說, 分片及副本的分配將是高可用及快速搜尋響應的設計核心.主分片與副本都能處理查詢請求,它們的唯一區別在於只有主分片才能處理索引請求.副本對搜尋效能非常重要,同時使用者也可在任何時候新增或刪除副本。額外的副本能給帶來更大的容量, 更高的呑吐能力及更強的故障恢復能力。

  • 深度查詢:在Elasticsearch中如果需要做分頁查詢,我們通常使用form和size實現。form指定從有序哪一行開始,size表示從當前開始讀取多少行。但是我們發現查詢結果最大隻能到10000,這是因為Elasticsearch中的size的預設值在index.max_result_window 中設定,並且預設值就是10000,如果需要擴充套件,可以通過如下操作【擴大查詢最大值】其中1000000是標識擴大為10萬:

   put /tenant_1_books/_settings
    { 
        "index.max_result_window" :"1000000"
    }

還可以採用searchAfer、scroll等方案。

YC.ElasticSearch 模組實戰

叢集部署

在本地或者伺服器上搭建3個es節點,形成叢集,針對elasticsearch.yml 進行節點配置,最後啟動服務,並安裝對應的kibana元件【視覺化】。

配置

在專案的YC.ServiceWebApi 中的配置檔案 DefaultConfig.json,做如下配置,其中node是對應的es節點。


  "ElasticSearchSetting": {

    ///elasticSearch節點叢集
    "Nodes": [
      { "node": "http://127.0.0.1:9200" },
      { "node": "http://127.0.0.1:9201" },
      { "node": "http://127.0.0.1:9202" }

    ]
  }

在專案的YC.ServiceWebApi 找到 ElasticSearchAutofacModule.cs 該檔案是相關的IOC 注入配置,在Startup.cs中進行如下注入操作:

 // elasticSearch 注入
builder.RegisterModule(new ElasticSearchAutofacModule());

ES 模組呼叫

在示例演示 BookAppService 中可以直接使用對應的注入呼叫es元件。


      private IElasticSearchRepository<Book> _elasticSearchRepository;
       public BookAppService(
        IHttpContextAccessor httpContextAccessor, ICacheManager cacheManager, IMapper mapper, IElasticSearchRepository<Book> elasticSearchRepository) : base(httpContextAccessor, cacheManager)
        {
            _cacheManager = cacheManager;
            _mapper = mapper;
            _elasticSearchRepository = elasticSearchRepository;
        }

        /// <summary>
        /// 查查預設1頁10條
        /// </summary>
        /// <returns>返回資料集合</returns>

        public async Task<ApiResult<List<BookAddOrEditDto>>> GetAllAsync()
        {
            var res = new ApiResult<List<BookAddOrEditDto>>();
            var data = await _elasticSearchRepository.GetAllAsync();

            var entityDtoList = _mapper.Map<List<BookAddOrEditDto>>(data);
            return res.Ok(entityDtoList);
        }

YC.ElasticSearch 模組介紹

模組包含有請求上下文、以及預設倉儲,其中倉儲封裝了常規crud、聚合查詢、searchAfter查詢等常規操作非同步方法,並在倉儲上提供一個公開請求上下文物件,用於自定義化es操作,模組配套對應的單元測試,提供基礎呼叫示例。

es 其他使用介紹

  • 分詞

使用 kibana 操作,對指定的Index進行分詞

//建立表 對應的分片,需要表還沒建立時候設定
put /tenant_1_books_0
{
  "settings":{
    
    "number_of_shards":2
  }
}

  • 資料結構修改和遷移
 //建立新的索引資料庫,並指定欄位對映型別,tenant_1_books_0 中的bookName 型別改為keyword
PUT tenant_1_books_0
 {
  "mappings": {
    "properties": {
      
      "bookName":{
        "type":"keyword"
      }
    }
    
  }
  
 }

  //遷移資料,將tenant_1_books 資料遷移到tenant_1_books_1
 POST _reindex
 {
  "source": {
    "index": "tenant_1_books"
    
  },
  "dest": {
     "index": "tenant_1_books_1"
    
  }
 }
  • 分頁查詢
//檢視tenant_1_books所有資料【預設會分頁】
GET tenant_1_books/_search
{
  "track_total_hits": true,
  "query": {
    "match_all": {}
  }
}
//深度分頁方案1 擴大分頁限制
//允許深度分頁,限制在10w
put /tenant_1_books/_settings
{
     "index.max_result_window" :"1000000"
}
//查詢資料 分頁,track_total_hits=真實的總數
GET tenant_1_books/_search
{
  "track_total_hits": true,
  "from" : 99000, "size" : 100,
  "query": {
    "match_all": {}
  }
}

結果如下:

  • 深度查詢 searchAfter

配套的net單元測試程式碼如下:

        /// <summary>
        /// 深度分頁查詢 searchAfter
        /// </summary>
        /// <returns></returns>
        [Fact]
        public async Task GetPageByQuerySearchAfterTest()
        {
            int size = 100;
            // "bookName" : {
            //"type" : "keyword"
            //},
            //1、BookName 修改為keyword 所有必須完整匹配,不分詞
            Func<QueryContainerDescriptor<Book>, QueryContainer> query1 = q => q.Term(t => t.BookName, "吞噬星空");
            Func<QueryContainerDescriptor<Book>, QueryContainer> query2 = q => q.Match(mq =>
              mq.Field(f => f.BookName).Query("哈利波特").Operator(Operator.And)
              );//由於型別為 keyword,所以Match 查詢不出來,只能使用Term 精確查詢

            //2.全字匹配+ 分詞查詢
            Func<QueryContainerDescriptor<Book>, QueryContainer> query3 = q => q
                           .Term(t => t.BookName, "吞噬星空")
                           || q.Match(mq =>
               mq.Field(f => f.BookContent).Query("哈利波特").Operator(Operator.And)
              );
            //排序
            Func<SortDescriptor<Book>, IPromise<IList<ISort>>> sort = s => s.Ascending(a => a.CreateDate).Descending(d=>d.Price);

          var result1=await  _elasticSearchRepository.GetPageByQuerySearchAfterAsync(query3, sort, 100, null);
            //使用上一次查詢得到SearchAfter 作為下一次查詢的遊標
            var result2 = await _elasticSearchRepository.GetPageByQuerySearchAfterAsync(query3, sort, 100, result1.SearchAfter);

            Assert.NotNull(result2.List);
        }
  • scroll 查詢
//深度分頁方案3 scroll,者每次查詢大量的文件,但是對實時性要求並不高,
//後面的每次滾屏(或者叫翻頁)都是基於這個快照的結果,也就是即使有新的資料進來也不會別查詢到。
//1. 查詢
POST tenant_1_books/_search?scroll=1m
{
    "size": 1000,
    "query": {
        "match_all" : {
        }
    }
   
  }
//2. 上一次查詢所得到結果,作為遊標
POST _search/scroll
{
    "scroll" : "1m",
    "scroll_id" : "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFmJpVWRZVWQ3UkItejk2UUx5bC15bFEAAAAAAAMv2xZyZURRWkowelF6S0NnRjMzWjhfQTh3"
  
}
  • 聚合查詢
//聚合獲取該欄位的所有統計
get /tenant_1_books/_search
{
   "aggs":{
      "extended_stats_price":{"extended_stats":{"field":"price"}}
   }
}
//聚合 總和統計
get /tenant_1_books/_search
{
   "aggs":{
      "total_price":{"sum":{"field":"price"}}
   }
}

YC.ElasticSearch 大資料檢索示例

http://yc.yc-l.com/ 演示站點中,預設使用租戶1 作為es 檢索演示,內建1000多萬條測試資料,通過 書名、書內容關鍵詞、釋出時間範圍等可進行查詢, 價格 查詢在演示站點中關閉了,無法查詢,請注意。

備註:演示站點預設使用10000條資料查詢上限邊界。

相關文章