主頁 > 後端開發 > 3 - 基于ELK的ElasticSearch 7.8.x技術整理 - 高級篇( 偏理論 )

3 - 基于ELK的ElasticSearch 7.8.x技術整理 - 高級篇( 偏理論 )

2022-01-03 06:08:00 後端開發

4、ES高級篇

4.1、集群部署

  • 集群的意思:就是將多個節點歸為一體罷了( 這個整體就有一個指定的名字了 )

4.1.1、window中部署集群 - 了解即可

  • 把下載好的window版的ES中的data檔案夾、logs檔案夾下的所有的檔案刪掉,然后拷貝成三份,對檔案重命名

image

  • 修改node-1001節點的config/elasticsearch.yml組態檔

  • 這個組態檔里面有原生的配置資訊,感興趣的可以查看,因為現在要做的配置資訊都在原生的配置資訊里,只是被注釋掉了而已,當然:沒興趣的,直接全選刪掉,然后做如下配置



# ---------------------------------- Cluster -----------------------------------
#
# Use a descriptive name for your cluster:
# 集群名稱  注意:是把多個節點歸為一個整體,所以這個集群名字就是各節點歸為一體之后的名字
# 因此:各個節點中這個集群名字也就要一樣了
cluster.name: es-colony
#
# ------------------------------------ Node ------------------------------------
#
# Use a descriptive name for the node:
# 節點名稱  在一個集群中,這個名字要全域唯一
node.name: node-1001
# 是否有資格成為主機節點
node.master: true
# 是否是資料節點
node.data: true
#
# ---------------------------------- Network -----------------------------------
#
# Set the bind address to a specific IP (IPv4 or IPv6):
# 當前節點的ip地址
network.host: 127.0.0.1
#
# Set a custom port for HTTP:
# 當前節點的埠號
http.port: 1001
# 當前節點的通訊埠( 監聽埠 )
transport.tcp.port: 9301
# 跨域配置
http.cors.enabled: true
http.cors.allow-origin: "*"


  • 修改node-1002節點的config/elasticsearch.yml組態檔



# ---------------------------------- Cluster -----------------------------------
#
# Use a descriptive name for your cluster:
# 集群名稱  注意:是把多個節點歸為一個整體,所以這個集群名字就是各節點歸為一體之后的名字
# 因此:各個節點中這個集群名字也就要一樣了
cluster.name: es-colony
#
# ------------------------------------ Node ------------------------------------
#
# Use a descriptive name for the node:
# 節點名稱  在一個集群中,這個名字要全域唯一
node.name: node-1002
# 是否是主機節點
node.master: true
# 是否是資料節點
node.data: true
#
# ---------------------------------- Network -----------------------------------
#
# Set the bind address to a specific IP (IPv4 or IPv6):
# 當前節點的ip地址
network.host: 127.0.0.1
#
# Set a custom port for HTTP:
# 當前節點的埠號
http.port: 1002
# 當前節點的通訊埠( 監聽埠 )
transport.tcp.port: 9302
# 當前節點不知道集群中另外節點是哪些澀,所以配置,讓當前節點能夠找到其他節點
discovery.seed_hosts: ["127.0.0.1:9301"]
# ping請求呼叫超時時間,但同時也是選主節點的delay time
discovery.zen.fd.ping_timeout: 1m
# 重試次數,防止GC[ 垃圾回收 ]節點不回應被剔除
discovery.zen.fd.ping_retries: 5
# 跨域配置
http.cors.enabled: true
http.cors.allow-origin: "*"


修改node-1003節點的config/elasticsearch.yml組態檔



# ---------------------------------- Cluster -----------------------------------
#
# Use a descriptive name for your cluster:
# 集群名稱  注意:是把多個節點歸為一個整體,所以這個集群名字就是各節點歸為一體之后的名字
# 因此:各個節點中這個集群名字也就要一樣了
cluster.name: es-colony
#
# ------------------------------------ Node ------------------------------------
#
# Use a descriptive name for the node:
# 節點名稱  在一個集群中,這個名字要全域唯一
node.name: node-1003
# 是否是主機節點
node.master: true
# 是否是資料節點
node.data: true
#
# ---------------------------------- Network -----------------------------------
#
# Set the bind address to a specific IP (IPv4 or IPv6):
# 當前節點的ip地址
network.host: 127.0.0.1
#
# Set a custom port for HTTP:
# 當前節點的埠號
http.port: 1003
# 當前節點的通訊埠( 監聽埠 )
transport.tcp.port: 9303
# 當前節點不知道集群中另外節點是哪些澀,所以配置,讓當前節點能夠找到其他節點
discovery.seed_hosts: ["127.0.0.1:9301","127.0.0.1:9302"]
# ping請求呼叫超時時間,但同時也是選主節點的delay time
discovery.zen.fd.ping_timeout: 1m
# 重試次數,防止GC[ 垃圾回收 ]節點不回應被剔除
discovery.zen.fd.ping_retries: 5
# 跨域配置
http.cors.enabled: true
http.cors.allow-origin: "*"

依次啟動1、2、3節點的bin/elasticsearch.bat即可啟動集群

用postman測驗集群


http://localhost:1001/_cluster/health  # 請求方式:get

# 相應內容
{
    "cluster_name": "es-colony",
    "status": "green",  # 重點查看位置 狀態顏色
    "timed_out": false,
    "number_of_nodes": 3,	# 重點查看位置	集群中的節點數量
    "number_of_data_nodes": 3,		# 重點查看位置	集群中的資料節點數量
    "active_primary_shards": 0,
    "active_shards": 0,
    "relocating_shards": 0,
    "initializing_shards": 0,
    "unassigned_shards": 0,
    "delayed_unassigned_shards": 0,
    "number_of_pending_tasks": 0,
    "number_of_in_flight_fetch": 0,
    "task_max_waiting_in_queue_millis": 0,
    "active_shards_percent_as_number": 100.0
}

image

status欄位顏色表示:當前集群在總體上是否作業正常,它的三種顏色含義如下:

  1. green:所有的主分片和副本分片都正常運行,
  2. yellow:所有的主分片都正常運行,但不是所有的副本分片都正常運行,
  3. red:有主分片沒能正常運行

附加內容:一些配置說明,下面的一些配置目前有些人可能并沒有遇到,但是在這里留個印象吧,知道個大概和怎么去找就行了

官網地址: https://www.elastic.co/guide/en/elasticsearch/reference/current/modules.html

1、主節點 [ host區域 ]:



cluster.name: elastics   #定義集群名稱所有節點統一配置
node.name: es-0   # 節點名稱自定義
node.master: true  # 主節點,資料節點設定為 false
node.data: false   # 資料節點設定為true
path.data: /home/es/data   
path.logs: /home/es/logs   
bootstrap.mlockall: true        #啟動時鎖定記憶體
network.publish_host: es-0
network.bind_host: es-0
http.port: 9200
discovery.zen.ping.multicast.enabled: false
discovery.zen.ping_timeout: 120s
discovery.zen.minimum_master_nodes: 2 #至少要發現集群可做master的節點數,
client.transport.ping_timeout: 60s
discovery.zen.ping.unicast.hosts: ["es-0","es-1", "es-2","es-7","es-8","es-4","es-5","es-6"] 
discovery.zen.fd.ping_timeout: 120s
discovery.zen.fd.ping_retries: 6
discovery.zen.fd.ping_interval: 30s
cluster.routing.allocation.disk.watermark.low: 100GB
cluster.routing.allocation.disk.watermark.high: 50GB
node.zone: hot                     #磁盤區域,分為hot和stale,做冷熱分離
script.inline: true
script.indexed: true 
cluster.routing.allocation.same_shard.host: true
threadpool.bulk.type: fixed  
threadpool.bulk.size: 32 
threadpool.bulk.queue_size: 100
threadpool.search.type: fixed  
threadpool.search.size: 49 
threadpool.search.queue_size: 10000
script.engine.groovy.inline.aggs: on
index.search.slowlog.threshold.query.warn: 20s
index.search.slowlog.threshold.query.info: 10s
index.search.slowlog.threshold.query.debug: 4s
index.search.slowlog.threshold.query.trace: 1s
index.search.slowlog.threshold.fetch.warn: 2s
index.search.slowlog.threshold.fetch.info: 1600ms
index.search.slowlog.threshold.fetch.debug: 500ms
index.search.slowlog.threshold.fetch.trace: 200ms
index.indexing.slowlog.threshold.index.warn: 20s
index.indexing.slowlog.threshold.index.info: 10s
index.indexing.slowlog.threshold.index.debug: 4s
index.indexing.slowlog.threshold.index.trace: 1s
indices.fielddata.cache.size: 20%
indices.fielddata.cache.expire: "48h"
indices.cache.filter.size: 10%
index.search.slowlog.level: WARN

資料節點 [ stale區域 ]


cluster.name: elastics  # 集群名字
node.name: es-1     #節點名稱
node.master: false      # 不作為主節點,只存盤資料
node.data: true         # 做為資料節點
path.data: /data1/es-data,/data2/es-data,/data3/es-data  # 存盤目錄,可配置多個磁盤
path.logs: /opt/es/logs     # 日志目錄
bootstrap.mlockall: true    # 啟動時鎖定記憶體
network.publish_host: es-1  # 系結網卡
network.bind_host: es-1     # 系結網卡
http.port: 9200             # http埠
discovery.zen.ping.multicast.enabled: false       # 禁用多播,夸網段不能用多播
discovery.zen.ping_timeout: 120s                  
discovery.zen.minimum_master_nodes: 2             # 至少要發現集群可做master的節點數
client.transport.ping_timeout: 60s
discovery.zen.ping.unicast.hosts: ["es-0","es-1", "es-2","es-7","es-8","es-4","es-5","es-6"]     # 集群自動發現

# fd 是 fault detection 
# discovery.zen.ping_timeout 僅在加入或者選舉 master 主節點的時候才起作用;
# discovery.zen.fd.ping_timeout 在穩定運行的集群中,master檢測所有節點,以及節點檢測 master是否暢通時長期有用
discovery.zen.fd.ping_timeout: 120s                # 超時時間(根據實際情況調整)
discovery.zen.fd.ping_retries: 6                   # 重試次數,防止GC[垃圾回收]節點不回應被剔除
discovery.zen.fd.ping_interval: 30s                # 運行間隔

# 控制磁盤使用的低水位,默認為85%,意味著如果節點磁盤使用超過85%,則ES不允許在分配新的分片,當配置具體的大小如100MB時,表示如果磁盤空間小于100MB不允許分配分片
cluster.routing.allocation.disk.watermark.low: 100GB      #磁盤限額

# 控制磁盤使用的高水位,默認為90%,意味著如果磁盤空間使用高于90%時,ES將嘗試分配分片到其他節點,上述兩個配置可以使用API動態更新,ES每隔30s獲取一次磁盤的使用資訊,該值可以通過cluster.info.update.interval來設定
cluster.routing.allocation.disk.watermark.high: 50GB      # 磁盤最低限額

node.zone: stale                      # 磁盤區域,分為hot和stale,做冷熱分離
script.inline: true                   # 支持腳本
script.indexed: true 
cluster.routing.allocation.same_shard.host: true    #一臺機器部署多個節點時防止一個分配到一臺機器上,宕機導致丟失資料
threadpool.bulk.type: fixed    # 以下6行為設定thread_pool
threadpool.bulk.size: 32 
threadpool.bulk.queue_size: 100
threadpool.search.type: fixed  
threadpool.search.size: 49 
threadpool.search.queue_size: 10000
script.engine.groovy.inline.aggs: on
index.search.slowlog.threshold.query.warn: 20s    # 以下為配置慢查詢和慢索引的時間
index.search.slowlog.threshold.query.info: 10s
index.search.slowlog.threshold.query.debug: 4s
index.search.slowlog.threshold.query.trace: 1s
index.search.slowlog.threshold.fetch.warn: 2s
index.search.slowlog.threshold.fetch.info: 1600ms
index.search.slowlog.threshold.fetch.debug: 500ms
index.search.slowlog.threshold.fetch.trace: 200ms
index.indexing.slowlog.threshold.index.warn: 20s
index.indexing.slowlog.threshold.index.info: 10s
index.indexing.slowlog.threshold.index.debug: 4s
index.indexing.slowlog.threshold.index.trace: 1s

4.1.2、linux中部署ES

4.1.2.1、部署單機ES
  • 準備作業
    • 1、下載linux版的ES,自行百度進行下載,老規矩,我的版本是:7.8.0
    • 2、將下載好的linux版ES放到自己的服務器中去

image

  • 解壓檔案:命令 tar zxvf elasticsearch-7.8.0-linux-x86_64.tar.gz
    image

  • 對檔案重命名: 命令 mv elasticsearch-7.8.0 es
    image

  • 創建用戶

  • 因為安全問題, Elasticsearch 不允許 root 用戶直接運行,所以要創建新用戶,在 root 用戶中創建新用戶

點擊查看代碼

useradd es		# 新增 es 用戶
passwd es		# 為 es 用戶設定密碼,輸入此命令后,輸入自己想設定的ES密碼即可
userdel -r es	# 如果錯了,可以把用戶洗掉了再重新加
chown -R es:es /opt/install/es		# 檔案授權		注意:/opt/install/es 改成自己的ES存放路徑即可

  • 修改 config/elasticsearch.yml 組態檔
點擊查看代碼

# 在elasticsearch.yml檔案末尾加入如下配置
cluster.name: elasticsearch
node.name: node-1
network.host: 0.0.0.0
http.port: 9200
cluster.initial_master_nodes: ["node-1"]

image

最后:保存 怕你是個大哥不會linux 操作方式 ——— 先按ESC 然后按shift+;分號 最后輸入wq即可

  • 后面懶得說操作方式,linux都不會的話,開什么玩笑

  • 修改 /etc/security/limits.conf 檔案 命令 vim /etc/security/limits.conf

點擊查看代碼

# 在檔案末尾中增加下面內容
# 這個配置是:每個行程可以打開的檔案數的限制
es soft nofile 65536
es hard nofile 65536

  • 修改 /etc/security/limits.d/20-nproc.conf 檔案 命令 vim /etc/security/limits.d/20-nproc.conf
點擊查看代碼

# 在檔案末尾中增加下面內容
# 每個行程可以打開的檔案數的限制
es soft nofile 65536
es hard nofile 65536
# 作業系統級別對每個用戶創建的行程數的限制
* hard nproc 4096
# 注: * 表示 Linux 所有用戶名稱

image

  • 修改 /etc/sysctl.conf 檔案
點擊查看代碼

# 在檔案中增加下面內容
# 一個行程可以擁有的 VMA(虛擬記憶體區域)的數量,默認值為 65536
vm.max_map_count=655360

  • 重新加載檔案
點擊查看代碼
# 命令
sysctl -p
  • 啟動程式 : 準備進入坑中

點擊查看代碼

cd /opt/install/es/
# 啟動
bin/elasticsearch
# 后臺啟動
bin/elasticsearch -d 

image

  • 這個錯誤告知:不能用root用戶,所以:切換到剛剛創建的es用戶 命令 su es
  • 然后再次啟動程式,進入下一個坑

image

  • 這個錯誤是因為:啟動程式的時候會動態生成一些檔案,這和ES沒得關系,所以:需要切回到root用戶,然后把檔案權限再次重繪一下
點擊查看代碼
# 切換到root用戶
su root

# 切換到root用戶之后,執行此命令即可
chown -R es:es /opt/install/es

# 再切換到es用戶
su es

image

  • 再次啟動程式
    image

  • 吃雞,這樣linux中單機ES就部署成功了

不過啊,前面這種方式都是low的方式,有更簡單的方式,就是使用docker容器來進行配置,簡直不要太簡單,雖然:使用docker容器來啟動程式有弊端,如:MySQL就不建議放在docker容器中,因為:MySQL是不斷地進行io操作,放到docker容器中,就會讓io操作效率降低,而ES放到docker中也是同樣的道理,但是:可以玩,因為:有些公司其實并沒有在意docker的弊端,管他三七二十一扔到docker中

  • 如果想要用docker容器進行ES配置,撰寫如下的docker-compose.yml檔案
點擊查看代碼

version: "3.1"
services:
  elasticsearch:
    image: daocloud.io/library/elasticsearch:7.9.0  # 注:此網站版本不全,可以直接用管我elasticsearch:7.8.0
    restart: always
    container_name: elasticsearch
    ports:
      - 9200:9200
    environment:
      - JAVA_OPTS=--Xms256m -Xmx1024m

  • 然后啟動容器即可

  • 注:使用docker安裝需要保證自己的linux中安裝了docker和docker-compose,沒有安裝的話,教程鏈接如下:

    • https://www.cnblogs.com/xiegongzi/p/15621992.html
  • 測驗是否成功


# 在瀏覽器和postman中輸入以下指令均可
 http://ip:9200/		# 注:ip是自己服務器的ip    如果是用postman,則:請求方式為 get

  • 瀏覽器效果
    image

    • 注:瀏覽器訪問不了,看看自己服務器開放9200埠沒有,別搞這種扯犢子事啊
  • postman的效果
    image

4.1.2.2、部署集群ES
  • 最簡單易懂但復雜的方式:對照windows版的集群就可以了

    • 解壓ES、重命名
    • 復制幾份ES檔案夾
    • 修改對應配置
  • 更簡單的方式

    • 解壓linux版的ES,重命名
    • 分發節點

	xsync  es-colony		# es-colony就是重命名之后的es檔案夾

  • 注:要是沒有配置xsync,則:需要單獨配置好,面向百度吧,很簡單的,就使用yum命令安裝rsync、添加hosts資訊、編輯xsync腳本、給檔案授權,然后就搞定了

4.2、鞏固核心概念

4.2.1、索引 index

  • 所謂索引:類似于關系型資料庫中的資料庫

  • 但是索引這個東西在ES中又有點東西,它的作用和關系型資料庫中的索引是一樣的,相當于門牌號,一個標識,旨在:提高查詢效率,當然,不是說只針對查詢,CRUD都可以弄索引,所以這么一說ES中的索引和關系型資料庫中的索引是一樣的,就不太類似于關系型中的資料庫了,此言差矣!在關系型中有了資料庫,才有表結構( 行、列、型別...... ),而在ES中就是有了索引,才有doc、field.....,因此:這就類似于關系型中的資料庫,只是作用和關系型中的索引一樣罷了

  • 因此:ES中索引類似于關系型中的資料庫,作用:類似于關系型中的索引,旨在:提高查詢效率,當然:在一個集群中可以定義N多個索引,同時:索引名字必須采用全小寫字母

  • 當然:也別忘了有一個倒排索引

    • 關系型資料庫通過增加一個B+樹索引到指定的列上,以便提升資料檢索速度,索引ElasticSearch 使用了一個叫做 倒排索引 的結構來達到相同的目的

4.2.2、型別 type

  • 這玩意兒就相當于關系型資料庫中的表,注意啊:關系型中表是在資料庫下,那么ES中也相應的 型別是在索引之下建立的

  • 表是個什么玩意呢?行和列嘛,這行和列有多少N多行和N多列嘛,所以:ES中的型別也一樣,可以定義N種型別,同時:每張表要存盤的資料都不一樣吧,所以表是用來干嘛的?分類 / 磁區嘛,所以ES中的型別的作用也來了:就是為了分類嘛,另外:關系型中可以定義N張表,那么在ES中,也可以定義N種型別

  • 因此:ES中的型別類似于關系型中的表,作用:為了分類 / 磁區,同時:可以定義N種型別,但是:型別必須是在索引之下建立的( 是索引的邏輯體現嘛 )

  • 但是:不同版本的ES,型別也發生了變化,上面的解讀不是全通用的

    • image

4.2.3、檔案 document

  • 這玩意兒類似管關系型中的行, 一個檔案是一個可被索引的基礎資訊單元,也就是一條資料嘛

4.2.4、欄位field

  • 這也就類似于關系型中的列, 對檔案資料根據不同屬性( 列欄位 )進行的分類標識

4.2.5、映射 mapping

  • 指的就是:結構資訊 / 限制條件
  • 還是對照關系型來看,在關系型中表有哪些欄位、該欄位是否為null、默認值是什么........諸如此的限制條件,所以ES中的映射就是:資料的使用規則設定

4.2.6、分片 shards - 重要

  • 這玩意兒就類似于關系型中的分表

  • 在關系型中如果一個表的資料太大了,查詢效率很低、回應很慢,所以就會采用大表拆小表,如:用戶表,不可能和用戶相關的啥子東西都放在一張表吧,這不是找事嗎?因此:需要分表

  • 相應的在ES中,也需要像上面這么干,如:存盤100億檔案資料的索引,在單節點中沒辦法存盤這么多的檔案資料,所以需要進行切割,就是將這整個100億檔案資料切幾刀,然后每一刀切分出來的每份資料就是一個分片 ( 索引 ),然后在切開的每份資料單獨放在一個節點中,這樣切開的所有檔案資料合在一起就是一份完整的100億資料,因此:這個的作用也是為了提高效率

  • 創建一個索引的時候,可以指定想要的分片的數量,每個分片本身也是一個功能完善并且獨立的“索引”,這個“索引”可以被放置到集群中的任何節點上

  • 分片有兩方面的原因:

    • 允許水平分割 / 擴展內容容量,水平擴充,負載均衡嘛
    • 允許在分片之上進行分布式的、并行的操作,進而提高性能 / 吞吐量
  • 注意啊: 當 Elasticsearch 在索引中搜索的時候, 它發送查詢到每一個屬于索引的分片,然后合并每個分片的結果到一個全域的結果集中

4.2.7、副本 Replicas - 重要

  • 這不是游戲中的刷副本的那個副本啊,是指:分片的復制品

  • 失敗是常有的事嘛,所以:在ES中也會失敗呀,可能因為網路、也可能因此其他鬼原因就導致失敗了,此時不就需要一種故障轉移機制嗎,也就是 創建分片的一份或多份拷貝,這些拷貝就叫做復制分片( 副本 )

  • 副本( 復制分片 )之所以重要,有兩個原因:

    • 在分片 / 節點失敗的情況下,提供了高可用性,因為這個原因,復制分片不與原 / 主要( original / primary )分片置于同一節點上是非常重要的
    • 擴展搜索量 / 吞吐量,因為搜索可以在所有的副本上并行運行
  • 多說一嘴啊,分片和副本這兩個不就是配套了嗎,分片是切割資料,放在不同的節點中( 服務中 );副本是以防服務宕掉了,從而丟失資料,進而把分片拷貝了任意份,這個像什么?不就是Redis中的主備機制嗎( 我說的是主備機制,不是主從復制啊 ,這兩個有區別的,主從是一臺主機、一臺從機,主、從機都具有讀寫操作;而主備是一臺主機、一臺從機,主機具有讀寫操作,而從機只有讀操作 ,不一樣的啊 )

  • 不過,有個細節一定需要注意啊,在Redis中是主備放在一臺服務器中,而在ES中,分片和副本不是在同一臺服務器中,是分開的,如:分片P1在節點1中,那么副本R1就不能在節點1中,而是其他服務中,不然服務宕掉了,那資料不就全丟了嗎

4.2.8、分配 Allocation

  • 前面講到了分片和副本,對照Redis中的主備來看了,那么對照Redis的主從來看呢?主機宕掉了怎么重新選一個主機?Redis中是加了一個哨兵模式,從而達到的,那么在ES中哪個是主節點、哪個是從節點、分片怎么去分的?就是利用了分配

  • 所謂的分配是指: 將分片分配給某個節點的程序,包括分配主分片或者副本,如果是副本,還包含從主分片復制資料的程序,注意:這個程序是由 master 節點完成的,和Redis還是有點不一樣的啊

  • 既然都說了這么多,那就再來一個ES的系統架構吧

image

  • 其中,P表示分片、R表示副本

  • 默認情況下,分片和副本都是1,根據需要可以改變

4.3、單節點集群

這里為了方便就使用window版做演示,就不再linux中演示了

  • 打開前面玩的window版集群的1節點

image

  • 創建索引 把這個索引切成3份( 切片 )、每份拷貝1份副本
http://127.0.0.1:1001/users		# 請求方式:put

# 請求體內容
{
    "settings" : {
        "number_of_shards" : 3,
        "number_of_replicas" : 1
    }
}

image

  • 開始安裝head插件,這就是一個可視化界面而已,后續還會用Kibana

    • 自行到官網下載elasticsearch-head-master,這是用Vue寫的

    • 這個插件有兩種安裝方式,chrome瀏覽器直接把這個壓縮包解壓之后,有一個crx檔案,進去之后有一個.crx結尾的檔案,改后綴為.rar,然后解壓,就可以得到一個檔案夾,然后把解壓的檔案夾拖到擴展程式中去,這就成為一個插件,集成到Chrome中去了,也就可以直接用了

    • 還有一種是通過Vue的方式,這種需要保證自己的電腦安裝了Node.js,我想都是玩過前后端分離的,也就玩過Vue了,所以這些Vue的配套安裝也就有了的 —— 安裝Node.js也不難,就官網下載、解壓、配置環境變數、然后進到解壓的elasticsearch-head-master目錄,使用npm install拉取模塊,最后使用npm run start就完了,當然npm是國外的,很慢,而使用淘寶的cnpm更快,cnpm安裝方式更簡單,直接npm install -g cnpm --registry=https://registry.npm.taobao.org拉取鏡像即可,然后就可以使用cnpm來代替npm,從而執行命令了

    • 由于我用的是Edge瀏覽器( Edge也可以像上面那么做,只是我偏不做,順便用來回顧一下Vue ),所以我是采用的Vue方式啟動的elasticsearch-head-master,啟動效果如下:

      • image

      • 訪問上圖中的地址即可,但是:這個埠是9100,而我們的ES事9200埠,所以9100訪問9200事跨越的,因此:需要對ES設定跨越問題,而這個問題在第一次玩ES集群時就配置了的

        • image
  • head打開之后就是下圖中的樣子

image

  • head鏈接ES之后就是下圖的樣子
    image

  • 三種顏色再鞏固一下:

    • green:所有的主分片和副本分片都正常運行
    • yellow:所有的主分片都正常運行,但不是所有的副本分片都正常運行
    • red:有主分片沒能正常運行
  • 但是:上述的單節點集群有問題,就是將分片和副本都放在一個節點( node-1001 )中了,這樣會導致前面說的服務宕掉,資料就沒了,做的副本就是無用功

  • 當然:在head中測驗時,可能會報master_not_discovered_exception,但是再啟動一個節點node-1002之后,發現又可以得吃了,而head界面中的顏色從yellow變成green了,這種情況是因為:原有資料導致的,即前面玩windows版ES集群時有另外的資料在里面,只需要把目錄下的data檔案夾和logs檔案夾“下”,把它的東西刪了再啟動就可以了

  • 但是啊,這里一是玩的windows版,二是為了玩ES才這么干的,這種方式別輕易干啊,學習階段還是多上網查一下,有很多解決方案的,這里是玩才搞的

  • 回到正題,怎么解決這個集群問題?

4.4、故障轉移

  • 這個東西其實已經見到了,就是前面說的報master_not_discovered_exception的情況,此時再啟動一個節點即可實作故障轉移

  • 啟動node-1002節點

image

  • 一樣的,可能由于玩windows版時的一些資料導致node-1002節點啟動不了,所以刪掉data檔案夾和logs檔案夾下的東西即可

  • 重繪head可視化頁面
    image

  • 恢復正常

4.5、水平擴容 / 負載均衡

  • 啟動node-1003節點
    image

  • 重繪head頁面
    image

  • 對照前面單節點集群來看,資料就被很好的分開了,這樣性能不就提上來了嗎?試問是去一個節點上訪問資料快還是把資料分開之后,減少壓力從而效率快呢?肯定后者嘛

  • 但是:如果相應繼續擴容呢?即:超過6份資料( 6個節點,前面講到過索引切分之后,每一份又是單獨的索引、副本也算節點 ),那怎么辦?

    • 首先知道一個點:主分片的數目在索引創建時就已經確定下來了的,這個我們沒法改變,這個數目定義了這個索引能夠存盤的最大資料量( 實際大小取決于你的資料、硬體和使用場景 )
    • 但是,讀操作——搜索和回傳資料——可以同時被主分片 或 副本分片所處理,所以當你擁有越多的副本分片時,也將擁有越高的吞吐量
    • 因此:增加副本分片的數量即可
	http://127.0.0.1:1001/users/_settings		# 請求方式:put

	# 請求體內容
	{
		"number_of_replicas": 2
	}

image

  • 重繪head頁面
    image

4.6、應對故障

  • 應對的是什么故障?前面一直在說:服務宕掉了嘛

  • 關掉node-1001節點( 主節點 )

  • 重繪head頁面
    image

  • 但是注意啊:yellow雖然不正常,但是不影響操作啊,就像你看了這個yellow之后,影響你正常發揮嗎?只是可能有點虛脫而已,所以對于ES來說也是可以正常查詢資料的,只是:效率降低了而已嘛( 主節點和3個分片都在的嘛 )

  • 解決這種問題

    • 開啟新節點( 把node-1001節點啟動 ———— 此時它就不是主節點了 ,當初新節點了嘛
      • image
        • 這就會報錯: unless existing master is discovered 找不到主節點( 對于啟動的集群來說,它現在是新節點澀 ),因此:需要做一下配置修改( node-1001的config/ElasticSearch.yml )

	discovery.seed_hosts: ["127.0.0.1:9302","127.0.0.1:9303"]

  • 保存開啟node-1001節點即可
    image

    • 重繪head頁面
      image

    • 故障恢復了,所以:這也告知一個問題,配置集群時,最好在每個節點的組態檔中都加上上述的配置,從而節點宕掉之后,重啟節點即可( 不然每次改不得煩死 ),注意:ES版本不一樣,這個配置方法不一樣的,6.x的版本是用cluster.initial_master_nodes: 來進行配置的

4.7、路由計算和分片控制理論

4.7.1、路由計算

  • 路由、路由,這個東西太熟悉了,在Vue中就見過路由router了( 用來轉發和重定向的嘛 )
  • 那在ES中的路由計算又是怎么回事?這個主要針對的是ES集群中的存資料,試想:你知道你存的資料是在哪個節點 / 哪個主分片中嗎( 副本是拷貝的主分片,所以主分片才是核心 )?
    • 當然知道啊,就是那幾個節點中的任意一個嘛,娘希匹~這樣的騷回答好嗎?其實這是由一個公式來決定的

	shard = hash( routing ) % number_of_primary_shards

其中

  • routing是一個任意值,默認是檔案的_id,也可以自定義
  • number_of_primary_shards 表示主分片的數量( 如前面切分為了3份 )
  • hash()是一個hash函式嘛

這就解釋了為什么我們要在創建索引的時候就確定好主分片的數量并且永遠不會改變這個數量:因為如果數量變化了,那么之前所有路由的值都會無效,檔案也再也找不到了

4.7.2、分片控制

  • 既然有了存資料的問題,那當然就有取資料的問題了,請問:在ES集群中,取資料時,ES怎么知道去哪個節點中取資料( 假如在3節點中,你去1節點中,可以取到嗎?),因此:來了分片控制

  • 其實ES不知道資料在哪個節點中,但是:你自己卻可以取到資料,為什么?

    • 負載均衡澀,輪詢嘛,所以這里有個小知識點,就是:協調節點 coordinating node我們可以發送請求到集群中的任一節點,每個節點都有能力處理任意請求,每個節點都知道集群中任一檔案位置,這就是分片控制,而我們發送請求的哪個節點就是:協調節點,它會去幫我們找到我們要的資料在哪里
  • 因此:當發送請求的時候, 為了擴展負載,更好的做法是輪詢集群中所有的節點( 先知道這樣做即可 )

4.8、資料寫流程

  • 新建、索引和洗掉請求都是寫操作, 必須在主分片上面完成之后才能被復制到相關的副本分片

  • 整個流程也很簡單

    • 客戶端請求任意節點( 協調節點 )
    • 通過路由計算,協調節點把請求轉向指定的節點
    • 轉向的節點的主分片保存資料
    • 主節點再將資料轉發給副本保存
    • 副本給主節點反饋保存結果
    • 主節點給客戶端反饋保存結果
    • 客戶端收到反饋結果

image

  • 但是:從圖中就可以看出來,這套流程完了,才可以做其他事( 如:才可以去查詢資料 ),那我為什么不可以異步呢?就是我只要保證到了哪一個步驟之后,就可以進行資料查詢,所以:這里有兩個小東西需要了解

  • 在進行寫資料時,我們做個小小的配置

4.8.1、一致性 consistency

  • 這玩意就是為了和讀資料搭配起來嘛,寫入和讀取保證資料的一致性唄

  • 這玩意可以設定的值如下:

    • one :只要主分片狀態 ok 就允許執行寫操作,這種寫入速度快,但不能保證讀到最新的更改
    • all:這是強一致性,必須要主分片和所有副本分片的狀態沒問題才允許執行寫操作
    • quorum:這是ES的默認值啊, 即大多數的分片副本狀態沒問題就允許執行寫操作,這是折中的方法,write的時候,W>N/2,即參與寫入操作的節點數W,必須超過副本節點數N的一半,在這個默認情況下,ES是怎么判定你的分片數量的,就一個公式:int( primary + number_of_replicas) / 2 ) + 1
      • 注意:primary指的是創建的索引數量;number_of_replicas是指的在索引設定中設定的副本分片數,如果你的索引設定中指定了當前索引擁有3個副本分片,那規定數量的計算結果為:int( 1 primary + 3 replicas) / 2 ) + 1 = 3,如果此時你只啟動兩個節點,那么處于活躍狀態的分片副本數量就達不到規定數量,也因此你將無法索引和洗掉任何檔案

4.8.2、超時 timeout

  • 如果沒有足夠的副本分片會發生什么?Elasticsearch 會等待,希望更多的分片出現,默認情況下,它最多等待 1 分鐘, 如果你需要,你可以使用timeout引數使它更早終止,單位是毫秒,如:100就是100毫秒

  • 新索引默認有1個副本分片,這意味著為滿足規定數量應該需要兩個活動的分片副本, 但是,這些默認的設定會阻止我們在單一節點上做任何事情,為了避免這個問題,要求只有當number_of_replicas 大于1的時候,規定數量才會執行

上面的理論不理解、或者感覺枯燥也沒事兒,后面慢慢的就理解了,這里只是打個預防針、了解理論罷了

4.9、資料讀流程

  • 有寫流程,那肯定也要說一下讀流程嘛,其實和寫流程很像,只是變了那么一丟丟而已

  • 流程如下:

    • 客戶端發送請求到任意節點( 協調節點 )
    • 這里不同,此時協調節點會做兩件事:1、通過路由計算得到分片位置,2、還會把當前查詢的資料所在的另外節點也找到( 如:副本 )
    • 為了負載均衡( 可能某個節點中的訪問量很大嘛,減少一下壓力咯 ),所以就會對查出來的所有節點做輪詢操作,從而找到想要的資料( 因此:你想要的資料在主節點中有、副本中也有,但是:給你的資料可能是主節點中的,也可能是副本中的 ———— 看輪詢到的是哪個節點中的 )
    • 節點反饋結果
    • 客戶端收到反饋結果

image

當然:這里有個注意點啊( 需要結合前面說的一致性理論 )

  • 在檔案( 資料 )被檢索時,已經被索引的檔案可能已經存在于主分片上但是還沒有復制到副本分片, 在這種情況下,副本分片可能會報檔案不存在,但是主分片可能成功回傳檔案, 一旦索引請求成功回傳給用戶,檔案在主分片和副本分片都是可用的

4.10、更新操作流程和批量更新操作流程

4.10.1、更新操作流程

image

  • 1、客戶端向node 1發送更新請求,

  • 2、它將請求轉發到主分片所在的node 3 ,

  • 3、node 3從主分片檢索檔案,修改_source欄位中的JSON,并且嘗試重新索引主分片的檔案,如果檔案已經被另一個行程修改,它會重試步驟3 ,超過retry_on_conflict次后放棄,

  • 4、如果 node 3成功地更新檔案,它將新版本的檔案并行轉發到node 1和 node 2上的副本分片,重新建立索引,一旦所有副本分片都回傳成功,node 3向協調節點也回傳成功,協調節點向客戶端回傳成功

  • 當然:上面有個漏洞,就是萬一在另一個行程修改之后,當前修改行程又去修改了,那要是把原有的資料修改了呢?這不就成關系型資料庫中的“不可重復讀”了嗎?

    • 不會的,因為當主分片把更改轉發到副本分片時, 它不會轉發更新請求, 相反,它轉發完整檔案的新版本,注意點:這些更改將會“異步轉發”到副本分片,并且不能保證它們以相同的順序到達, 如果 ES 僅轉發更改請求,則可能以錯誤的順序應用更改,導致得到的是損壞的檔案

4.10.2、批量更新操作流程

  • 這個其實更容易理解,單檔案更新懂了,那多檔案更新就懂了嘛,多檔案就請求拆分唄

  • 所謂的多檔案更新就是:將整個多檔案請求分解成每個分片的檔案請求,并且將這些請求并行轉發到每個參與節點,協調節點一旦收到來自每個節點的應答,就將每個節點的回應收集整理成單個回應,回傳給客戶端

  • 原理圖的話:我就在網上偷一張了
    image

  • 其實mget 和 bulk API的模式就類似于單檔案模式,區別在于協調節點知道每個檔案存在于哪個分片中

4.11、再次回顧分片和倒排索引

4.11.1、分片

  • 所謂的分片就是:將索引切分成任意份嘛,然后得到的每一份資料都是一個單獨的索引

  • 分片完成后,我們存資料時,存到哪個節點上,就是通過shard = hash( routing ) % number_of_primary_shards得到的

  • 而我們查詢資料時,ES怎么知道我們要找的資料在哪個節點上,就是通過協調節點做到的,它會去找到和資料相關的所有節點,從而輪詢( 所以最后的結果可能是從主分片上得到的,也可能是從副本上得到的,就看最后輪詢到的是哪個節點罷了

4.11.2、倒排索引

  • 這個其實在基礎篇中一上來說明索引時就提到了,基礎篇鏈接如下:
    • https://www.cnblogs.com/xiegongzi/p/15684307.html

image

  • 圖中這里,是將內容( 關鍵字 )拆分了,然后來對應ID,所以:這里還有一種東西:分詞,后面會接觸Kibana,再做詳細介紹

  • 但是,那只是簡單提了一下而已,其實還有三個東西沒說明

4.11.2.1、詞條
  • 它是指:索引中的最小存盤或查詢單元,這個其實很好理解,白話文來講就是:字或者詞組,英文就是一個單詞,中文就是字或詞組嘛,比如:你要查詢的內容中的某一個字或詞組,這就是詞條唄
4.11.2.2、詞典
  • 這個就更簡單了,就是詞條的集合嘛,字或者詞組組成的內容唄
4.11.2.3、倒排表
  • 就是指:關鍵字 / 關鍵詞在索引中的位置 / 概率,有點類似于陣列,你查詢陣列中某個元素的位置,但是區別很大啊,我只是為了好理解,所以才這么舉例子的

4.12、后面的安排

  • 后續的內容,打算抽取出來,重新弄成一片小博客,知識點太多,看起來太費勁了

  • 讓我弄知識點的哪些半吊子,如果是從基礎篇:https://www.cnblogs.com/xiegongzi/p/15684307.html,到java操作篇:https://www.cnblogs.com/xiegongzi/p/15690534.html,老老實實看到現在的話,那么掌握的ES知識足夠了

  • 后續有時間就弄一個ES小Demo出來,沒時間就略過了

  • 后續的內容就是一些理論、Kibana、框架集成,重點是Kibana、框架集成

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/401382.html

標籤:Java

上一篇:JDK成長記21: ReentrantLock (4) 公平、非公平、可重入鎖是什么?

下一篇:Java+Eclipse+MySQL+Swing實作學生會考成績管理系統(免費完整專案)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more