使用Consul做服務發現的若幹姿勢

来源:https://www.cnblogs.com/bossma/archive/2018/10/08/9756809.html
-Advertisement-
Play Games

這兩年微服務越來越火,使用Consul的人也越來越多,這篇文章將結合Consul的官方文檔和自己的實際經驗,談一下Consul做服務發現的方式,文中儘量不依賴具體的框架和開發語言,從原理上進行說明,希望能夠講清楚幾個問題。 ...


從2016年起就開始接觸Consul,使用的主要目的就是做服務發現,後來逐步應用於生產環境,並總結了少許使用經驗。最開始使用Consul的人不多,為了方便交流創建了一個QQ群,這兩年微服務越來越火,使用Consul的人也越來越多,目前群里已有400多人,經常有人問一些問題,比如:

  • 服務註冊到節點後,其他節點為什麼沒有同步?
  • Client是乾什麼的?(Client有什麼作用?)
  • 能不能直接註冊到Server?(是否只有Server節點就夠了?)
  • 服務信息是保存在哪裡的?
  • 如果節點掛了健康檢查能不能轉移到別的節點?

有些人可能對服務註冊和發現還沒有概念,有些人可能使用過其它服務發現的工具,比如zookeeper,etcd,會有一些先入為主的經驗。這篇文章將結合Consul的官方文檔和自己的實際經驗,談一下Consul做服務發現的方式,文中儘量不依賴具體的框架和開發語言,從原理上進行說明,希望能夠講清楚上邊的幾個問題。


 

為什麼使用服務發現

防止硬編碼、容災、水平擴縮容、提高運維效率等等,只要你想使用服務發現總能找到合適的理由。

一般的說法是因為使用微服務架構。傳統的單體架構不夠靈活不能很好的適應變化,從而向微服務架構進行轉換,而伴隨著大量服務的出現,管理運維十分不便,於是開始搞一些自動化的策略,服務發現應運而生。所以如果需要使用服務發現,你應該有一些對服務治理的痛點。

但是引入服務發現就可能引入一些技術棧,增加系統總體的複雜度,如果你只有很少的幾個服務,比如10個以下,並且業務不怎麼變化,吞吐量預計也很穩定,可能就沒有必要使用服務發現。


 

Consul內部原理

下麵這張圖來源於Consul官網,很好的解釋了Consul的工作原理,先大致看一下。

首先Consul支持多數據中心,在上圖中有兩個DataCenter,他們通過Internet互聯,同時請註意為了提高通信效率,只有Server節點才加入跨數據中心的通信。

在單個數據中心中,Consul分為Client和Server兩種節點(所有的節點也被稱為Agent),Server節點保存數據,Client負責健康檢查及轉發數據請求到Server;Server節點有一個Leader和多個Follower,Leader節點會將數據同步到Follower,Server的數量推薦是3個或者5個,在Leader掛掉的時候會啟動選舉機制產生一個新的Leader。

集群內的Consul節點通過gossip協議(流言協議)維護成員關係,也就是說某個節點瞭解集群內現在還有哪些節點,這些節點是Client還是Server。單個數據中心的流言協議同時使用TCP和UDP通信,並且都使用8301埠。跨數據中心的流言協議也同時使用TCP和UDP通信,埠使用8302。

集群內數據的讀寫請求既可以直接發到Server,也可以通過Client使用RPC轉發到Server,請求最終會到達Leader節點,在允許數據輕微陳舊的情況下,讀請求也可以在普通的Server節點完成,集群內數據的讀寫和複製都是通過TCP的8300埠完成。


 

Consul服務發現原理

下麵這張圖是自己畫的,基本描述了服務發現的完整流程,先大致看一下。

首先需要有一個正常的Consul集群,有Server,有Leader。這裡在伺服器Server1、Server2、Server3上分別部署了Consul Server,假設他們選舉了Server2上的Consul Server節點為Leader。這些伺服器上最好只部署Consul程式,以儘量維護Consul Server的穩定。

然後在伺服器Server4和Server5上通過Consul Client分別註冊Service A、B、C,這裡每個Service分別部署在了兩個伺服器上,這樣可以避免Service的單點問題。服務註冊到Consul可以通過HTTP API(8500埠)的方式,也可以通過Consul配置文件的方式。Consul Client可以認為是無狀態的,它將註冊信息通過RPC轉發到Consul Server,服務信息保存在Server的各個節點中,並且通過Raft實現了強一致性。

最後在伺服器Server6中Program D需要訪問Service B,這時候Program D首先訪問本機Consul Client提供的HTTP API,本機Client會將請求轉發到Consul Server,Consul Server查詢到Service B當前的信息返回,最終Program D拿到了Service B的所有部署的IP和埠,然後就可以選擇Service B的其中一個部署並向其發起請求了。如果服務發現採用的是DNS方式,則Program D中直接使用Service B的服務發現功能變數名稱,功能變數名稱解析請求首先到達本機DNS代理,然後轉發到本機Consul Client,本機Client會將請求轉發到Consul Server,Consul Server查詢到Service B當前的信息返回,最終Program D拿到了Service B的某個部署的IP和埠。

圖中描述的部署架構筆者認為是最普適最簡單的方案,從某些預設配置或設計上看也是官方希望使用者採用的方案,比如8500埠預設監聽127.0.0.1,當然有些同學不贊同,後邊會提到其他方案。


 

Consul實際使用

為了更快的熟悉Consul的原理及其使用方式,最好還是自己實際測試下。

Consul安裝十分簡單,但是在一臺機器上不方便搭建集群進行測試,使用虛擬機比較重,所以這裡選擇了docker。這裡用了Windows 10,需要是專業版,因為Windows上的Docker依賴Hyper-V,而這個需要專業版才能支持。這裡對於Docker的使用不會做過多的描述,如果遇到相關問題請搜索一下。

安裝Docker

通過這個地址下載安裝:

https://store.docker.com/editions/community/docker-ce-desktop-windows

安裝完成後打開 Windows PowerShell,輸入docker –version,如果正常輸出docker版本就可以了。

啟動Consul集群

在 Windows PowerShell中執行命令拉取最新版本的Consul鏡像:

docker pull consul
 

然後就可以啟動集群了,這裡啟動4個Consul Agent,3個Server(會選舉出一個leader),1個Client。

#啟動第1個Server節點,集群要求要有3個Server,將容器8500埠映射到主機8900埠,同時開啟管理界面
docker run -d --name=consul1 -p 8900:8500 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=true --bootstrap-expect=3 --client=0.0.0.0 -ui
 
#啟動第2個Server節點,並加入集群
docker run -d --name=consul2 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=true --client=0.0.0.0 --join 172.17.0.2
 
#啟動第3個Server節點,並加入集群
docker run -d --name=consul3 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=true --client=0.0.0.0 --join 172.17.0.2
 
#啟動第4個Client節點,並加入集群
docker run -d --name=consul4 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=false --client=0.0.0.0 --join 172.17.0.2
 

第1個啟動容器的IP一般是172.17.0.2,後邊啟動的幾個容器IP會排著來:172.17.0.3、172.17.0.4、172.17.0.5。

這些Consul節點在Docker的容器內是互通的,他們通過橋接的模式通信。但是如果主機要訪問容器內的網路,需要做埠映射。在啟動第一個容器時,將Consul的8500埠映射到了主機的8900埠,這樣就可以方便的通過主機的瀏覽器查看集群信息。

進入容器consul1:

docker exec -it consul1 /bin/sh
 
#執行ls後可以看到consul就在根目錄
ls

輸入exit可以跳出容器。

服務註冊

自己寫一個web服務,用最熟悉的開發語言就好了,不過需要在容器中能夠跑起來,可能需要安裝運行環境,比如python、java、.net core等的sdk及web伺服器,需要註意的是Consul的docker鏡像基於alpine系統,具體運行環境的安裝請搜索一下。

這裡寫了一個hello服務,通過配置文件的方式註冊到Consul,服務的相關信息:

  • name:hello,服務名稱,需要能夠區分不同的業務服務,可以部署多份並使用相同的name註冊。
  • id:hello1,服務id,在每個節點上需要唯一,如果有重覆會被覆蓋。
  • address:172.17.0.5,服務所在機器的地址。
  • port:5000,服務的埠。
  • 健康檢查地址:http://localhost:5000/,如果返回HTTP狀態碼為200就代表服務健康,每10秒Consul請求一次,請求超時時間為1秒。

請將下麵的內容保存成文件services.json,並上傳到容器的/consul/config目錄中。

{
  "services": [
    {
      "id": "hello1",
      "name": "hello",
      "tags": [
        "primary"
      ],
      "address": "172.17.0.5",
      "port": 5000,
      "checks": [
        {
        "http": "http://localhost:5000/",
        "tls_skip_verify": false,
        "method": "Get",
        "interval": "10s",
        "timeout": "1s"
        }
      ]
    }
  ]
}
 

複製到consul config目錄:

docker cp {這裡請替換成services.json的本地路徑} consul4:/consul/config
 

重新載入consul配置:

consul reload
 

然後這個服務就註冊成功了。可以將這個服務部署到多個節點,比如部署到consul1和consul4,並同時運行。

服務發現

服務註冊成功以後,調用方獲取相應服務地址的過程就是服務發現。Consul提供了多種方式。

HTTP API方式:

curl http://127.0.0.1:8500/v1/health/service/hello?passing=false
 

返回的信息包括註冊的Consul節點信息、服務信息及服務的健康檢查信息。這裡用了一個參數passing=false,會自動過濾掉不健康的服務,包括本身不健康的服務和不健康的Consul節點上的服務,從這個設計上可以看出Consul將服務的狀態綁定到了節點的狀態。

如果服務有多個部署,會返回服務的多條信息,調用方需要決定使用哪個部署,常見的可以隨機或者輪詢。為了提高服務吞吐量,以及減輕Consul的壓力,還可以緩存獲取到的服務節點信息,不過要做好容錯的方案,因為緩存服務部署可能會變得不可用。具體是否緩存需要結合自己的訪問量及容錯規則來確定。

上邊的參數passing預設為false,也就是說不健康的節點也會返回,結合獲取節點全部服務的方法,這裡可以做到獲取全部服務的實時健康狀態,並對不健康的服務進行報警處理。

DNS方式:

hello服務的功能變數名稱是:hello.service.dc1.consul,後邊的service代表服務,固定;dc1是數據中心的名字,可以配置;最後的consul也可以配置。

官方在介紹DNS方式時經常使用dig命令進行測試,但是alpine系統中沒有dig命令,也沒有相關的包可以安裝,但是有人實現了,下載下來解壓到bin目錄就可以了。

curl -L https://github.com/sequenceiq/docker-alpine-dig/releases/download/v9.10.2/dig.tgz|tar -xzv -C /usr/local/bin
 

然後執行dig命令:

dig @127.0.0.1 -p 8600 hello.service.dc1.consul. ANY
 

如果報錯:parse of /etc/resolv.conf failed ,請將resolv.conf中的search那行刪掉。

正常的話可以看到返回了服務部署的IP信息,如果有多個部署會看到多個,如果某個部署不健康了會自動剔除(包括部署所在節點不健康的情況)。需要註意這種方式不會返回服務的埠信息。

使用DNS的方式可以在程式中集成一個DNS解析庫,也可以自定義本地的DNS Server。自定義本地DNS Server是指將.consul域的請求全部轉發到Consul Agent,Windows上有DNS Agent,Linux上有Dnsmasq;對於非Consul提供的服務則繼續請求原DNS;使用DNS Server時Consul會隨機返回具體服務的多個部署中的一個,僅能提供簡單的負載均衡。

DNS緩存問題:DNS緩存一般存在於應用程式的網路庫、本地DNS客戶端或者代理,Consul Sever本身可以認為是沒有緩存的(為了提高集群DNS吞吐量,可以設置使用普通Server上的陳舊數據,但影響一般不大),DNS緩存可以減輕Consul Server的訪問壓力,但是也會導致訪問到不可用的服務。使用時需要根據實際訪問量和容錯能力確定DNS緩存方案。

Consul Template

Consul Template是Consul官方提供的一個工具,嚴格的來說不是標準的服務發現方式。這個工具會通過Consul監聽數據變化然後替換模板中使用的標簽,併發布替換後的文件到指定的目錄。在nginx等web伺服器做反向代理和負載均衡時特別有用。

Consul的docker鏡像中沒有集成這個工具,需要自己安裝,比較簡單:

curl -L https://releases.hashicorp.com/consul-template/0.19.5/consul-template_0.19.5_linux_amd64.tgz|tar -xzv -C /usr/local/bin
 

然後創建一個文件:in.tpl,內容為:

{{ range service "hello" }}
server {{ .Name }}{{ .Address }}:{{ .Port }}{{ end }}
 

這個標簽會遍歷hello服務的所有部署,並按照指定的格式輸出。在此文件目錄下執行:

nohup consul-template -template "in.tpl:out.txt" &
 

現在你可以cat out.txt查看根據模板生產的內容,新增或者關閉服務,文件內容會自動更新。

此工具我沒有用在生產環境,詳細使用請訪問:https://github.com/hashicorp/consul-template

節點和服務註銷

節點和服務的註銷可以使用HTTP API:

  • 註銷任意節點和服務:/catalog/deregister
  • 註銷當前節點的服務:/agent/service/deregister/:service_id

如果某個節點不繼續使用了,也可以在本機使用consul leave命令,或者在其它節點使用consul force-leave 節點Id。


 

Consul的健康檢查

Consul做服務發現是專業的,健康檢查是其中一項必不可少的功能,其提供Script/TCP/HTTP+Interval,以及TTL等多種方式。服務的健康檢查由服務註冊到的Agent來處理,這個Agent既可以是Client也可以是Server。

很多同學都使用ZooKeeper或者etcd做服務發現,使用Consul時發現節點掛掉後服務的狀態變為不可用了,所以有同學問服務為什麼不在各個節點之間同步?這個根本原因是服務發現的實現原理不同。

Consul與ZooKeeper、etcd的區別

後邊這兩個工具是通過鍵值存儲來實現服務的註冊與發現。

  • ZooKeeper利用臨時節點的機制,業務服務啟動時創建臨時節點,節點在服務就在,節點不存在服務就不存在。
  • etcd利用TTL機制,業務服務啟動時創建鍵值對,定時更新ttl,ttl過期則服務不可用。

ZooKeeper和etcd的鍵值存儲都是強一致性的,也就是說鍵值對會自動同步到多個節點,只要在某個節點上存在就可以認為對應的業務服務是可用的。

Consul的數據同步也是強一致性的,服務的註冊信息會在Server節點之間同步,相比ZK、etcd,服務的信息還是持久化保存的,即使服務部署不可用了,仍舊可以查詢到這個服務部署。但是業務服務的可用狀態是由註冊到的Agent來維護的,Agent如果不能正常工作了,則無法確定服務的真實狀態,並且Consul是相當穩定了,Agent掛掉的情況下大概率伺服器的狀態也可能是不好的,此時屏蔽掉此節點上的服務是合理的。Consul也確實是這樣設計的,DNS介面會自動屏蔽掛掉節點上的服務,HTTP API也認為掛掉節點上的服務不是passing的。

鑒於Consul健康檢查的這種機制,同時避免單點故障,所有的業務服務應該部署多份,並註冊到不同的Consul節點。部署多份可能會給你的設計帶來一些挑戰,因為調用方同時訪問多個服務實例可能會由於會話不共用導致狀態不一致,這個有許多成熟的解決方案,可以去查詢,這裡不做說明。

健康檢查能不能支持故障轉移?

上邊提到健康檢查是由服務註冊到的Agent來處理的,那麼如果這個Agent掛掉了,會不會有別的Agent來接管健康檢查呢?答案是否定的。

從問題產生的原因來看,在應用於生產環境之前,肯定需要對各種場景進行測試,沒有問題才會上線,所以顯而易見的問題可以屏蔽掉;如果是新版本Consul的BUG導致的,此時需要降級;如果這個BUG是偶發的,那麼只需要將Consul重新拉起來就可以了,這樣比較簡單;如果是硬體、網路或者操作系統故障,那麼節點上服務的可用性也很難保障,不需要別的Agent接管健康檢查。

從實現上看,選擇哪個節點是個問題,這需要實時或準實時同步各個節點的負載狀態,而且由於業務服務運行狀態多變,即使當時選擇出了負載比較輕鬆的節點,無法保證某個時段任務又變得繁重,可能造成新的更大範圍的崩潰。如果原來的節點還要啟動起來,那麼接管的健康檢查是否還要撤銷,如果要,需要記錄服務們最初註冊的節點,然後有一個監聽機制來觸發,如果不要,通過服務發現就會獲取到很多冗餘的信息,並且隨著時間推移,這種數據會越來越多,系統變的無序。

從實際應用看,節點上的服務可能既要被髮現,又要發現別的服務,如果節點掛掉了,僅提供被髮現的功能實際上服務還是不可用的。當然發現別的服務也可以不使用本機節點,可以通過訪問一個Nginx實現的若幹Consul節點的負載均衡來實現,這無疑又引入了新的技術棧。

如果不是上邊提到的問題,或者你可以通過一些方式解決這些問題,健康檢查接管的實現也必然是比較複雜的,因為分散式系統的狀態同步是比較複雜的。同時不要忘了服務部署了多份,掛掉一個不應該影響系統的快速恢復,所以沒必要去做這個接管。


 

Consul的其它部署架構

如果你實在不想在每個主機部署Consul Client,還有一個多路註冊的方案可供選擇,這是交流群中獲得的思路。

 

如圖所示,在專門的伺服器上部署Consul Client,然後每個服務都註冊到多個Client,這裡為了避免服務單點問題還是每個服務部署多份,需要服務發現時,程式向一個提供負載均衡的程式發起請求,該程式將請求轉發到某個Consul Client。這種方案需要註意將Consul的8500埠綁定到私網IP上,預設只有127.0.0.1。

這個架構的優勢:

  • Consul節點伺服器與應用伺服器隔離,互相干擾少;
  • 不用每台主機都部署Consul,方便Consul的集中管理;
  • 某個Consul Client掛掉的情況下,註冊到其上的服務仍有機會被訪問到;

但也需要註意其缺點:

  • 引入更多技術棧:負載均衡的實現,不僅要考慮Consul Client的負載均衡,還要考慮負載均衡本身的單點問題。
  • Client的節點數量:單個Client如果註冊的服務太多,負載較重,需要有個演算法(比如hash一致)合理分配每個Client上的服務數量,以及確定Client的總體數量。
  • 服務發現要過濾掉重覆的註冊,因為註冊到了多個節點會認為是多個部署(DNS介面不會有這個問題)。

這個方案其實還可以優化,服務發現使用的負載均衡可以直接代理Server節點,因為相關請求還是會轉發到Server節點,不如直接就發到Server。

是否可以只有Server?

這個問題的答案還是有關服務數量的問題,首先Server的節點數量不是越多越好,3個或者5個是推薦的數量,數量越多數據同步的處理越慢(強一致性);然後每個節點可以註冊的服務數量是有上限的,這個受限於軟硬體的處理能力。所以如果你的服務只有10個左右,只有Server問題是不大的,但是這時候有沒有必要使用Consul呢?因此正常使用Consul的時候還是要有Client才好,這也符合Consul的反熵設計。

大家可以將這個部署架構與前文提到的普世架構對比下,看看哪個更適合自己,或者你有更好的方案歡迎分享出來。


 

後記

在編寫這篇文章的時候,發現很多地方還不瞭解,很多框架也沒有使用過,增長了不少見識,同時確認了一些之前似是而非的細節,但是文中仍可能有些理解錯誤,或者說的不是很清楚的地方,比如如何結合容器在生產環境使用,歡迎大家加群交流(群號: 234939415)!

我的獨立博客:http://blog.bossma.cn/consul/consul-service-register-and-discovery-style/


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1》OL標簽的改良 start type reversed:翻轉排序 2》datalist標簽自動補全的使用 3》progress標簽的使用:進度條 4》meter標簽的應用 5》details展開收縮標簽的使用-子標簽summary(自動帶有展開收縮的效果) 6》mark標簽的應用:高亮顯示文本 ...
  • 隨著flash的沒落,瀏覽器的原生能力的興起。在3D方面WebGL不管從功能還是性能方面都在逐漸加強。2D應用變為3D應用的需求也越來越強烈。 win10的畫圖板支持3D圖片,2d工具photoshop也開始逐步集成了3D工具。 下麵就基於WebGL技術探討一下現在的兩款3D框架。Threejs(h ...
  • 網上很多關於驗證小數的正則表達式,但是很多都不是百分百正確,所以我結合一些前輩的經驗,自己寫了一個。 驗證非0開頭的無限位整數和小數。整數支持無限位,小數點前支持無限位,小數點後最多保留兩位。 js代碼如下: var reg = /^(([^0][0-9]+|0)\.([0-9]{1,2})$)|^ ...
  • 近幾年,微服務架構在後端技術社區大紅大紫,它被認為是IT軟體架構的未來技術方向.我們如何借鑒後端微服務的思想來構建一個現代化前端應用? 在這裡我提供一個可以在產品中真正可以落地的前端微服務解決方案. 微服務化後端前後端對比 後端微服務化的優勢: 1. 複雜度可控: 體積小、複雜度低,每個微服務可由一 ...
  • 在Bootstrap fileinput中移除預覽文件時可以通過配置initialPreviewConfig: [ { url:'deletefile',key:fileid } ] 來同步刪除伺服器上的文件和記錄。但新上傳的文件則需要其他方式來同步刪除伺服器記錄。 在配置中遇到的一些問題,記錄一下 ...
  • 數據流轉 先上一張圖看清 Westore 怎麼解決小程式數據難以管理和維護的問題: 非純組件的話,可以直接省去 triggerEvent 的過程,直接修改 store.data 並且 update,形成縮減版單向數據流。 "Github: https://github.com/dntzhang/we ...
  • 想在黑暗中看清周圍,不可避免地要用到夜視儀。那麼如果是想在黑暗中拍照,又沒有閃光燈,如何才能排到清晰的照片?在CVPR 2018上,英特爾實驗室的Vladlen Koltun和陳啟峰帶領的團隊提出了一種在黑暗中快速成像的系統,效果非常贊。 在暗光下的圖像易受到低信噪比和低亮度的影響。短曝光的照片會出 ...
  • 去年的時候寫過dubbo+zipkin調用鏈監控,最近看到zipkin2配合brave實現起來會比我之前的實現要簡單很多,因為brave將很多交互的內容都封裝起來了,不需要自己去寫具體的實現,比如如何去構建span,如何去上報數據。 收集器抽象 由於zipkin支持http以及kafka兩種方式上報 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...