微服務之間的最佳調用方式

来源:https://www.cnblogs.com/code-craftsman/archive/2019/09/20/11556672.html
-Advertisement-
Play Games

微服務之間的調用有兩種方式,RPC和事件驅動。事件驅動是更好的方式,因為它是松耦合的。但如果業務邏輯是緊耦合的,RPC方式也是可行的(它的好處是代碼更簡單),而且你還可以通過選取合適的協議(Protobuf+gRPC)來降低這種緊耦合帶來的危害。由於事件溯源和事件通知的相似性,很多人把兩者弄混了,但... ...


在微服務架構中,需要調用很多服務才能完成一項功能。服務之間如何互相調用就變成微服務架構中的一個關鍵問題。服務調用有兩種方式,一種是RPC方式,另一種是事件驅動(Event-driven)方式,也就是發消息方式。消息方式是松耦合方式,比緊耦合的RPC方式要優越,但RPC方式如果用在適合的場景也有它的一席之地.

耦合的種類:
我們總在談耦合,那麼耦合到底意味著什麼呢?

  1. 時間耦合:客戶端和服務端必須同時上線才能工作。發消息時,接受消息隊列必須運行,但後臺處理程式暫時不工作也不影響。
  2. 容量耦合:客戶端和服務端的處理容量必須匹配。發消息時,如果後臺處理能力不足也不要緊,消息隊列會起到緩衝的作用。
  3. 介面耦合:RPC調用有函數標簽,而消息隊列只是一個消息。例如買了商品之後要調用發貨服務,如果是發消息,那麼就只需發送一個商品被買消息。
  4. 發送方式耦合:RPC是點對點方式,需要知道對方是誰,它的好處是能夠傳回返回值。消息既可以點對點,也可以用廣播的方式,這樣減少了耦合,但也使返回值比較困難。

下麵我們來逐一分析這些耦合的影響。 第一,時間耦合,對於多數應用來講,你希望能馬上得到回答,因此即使使用消息隊列,後臺也需要一直工作。第二,容量耦合,如果你對回覆有時間要求,那麼消息隊列的緩衝功能作用不大,因為你希望及時響應。真正需要的是自動伸縮(Auto-scaling),它能自動調整服務端處理能力去匹配請求數量。第三和第四,介面耦合和發送方式耦合,這兩個確實是RPC方式的軟肋。

事件驅動(Event-Driven)方式:

Martin Fowler把事件驅動分成四種方式(What do you mean by “Event-Driven”),簡化之後本質上只有兩種方式。 一種就是我們熟悉的的事件通知(Event Notification),另一種是事件溯源(Event Sourcing)。事件通知就是微服務之間不直接調用,而是通過發消息來進行合作。事件溯源有點像記賬,它把所有的事件都記錄下來,作為永久存儲層,再在它的基礎之上構建應用程式。實際上從應用的角度來講,它們並不應該分屬一類,它們的用途完全不同。事件通知是微服務的調用(或集成)方式,應該和RPC分在一起。事件溯源是一種存儲數據的方式,應該和資料庫分在一起。

事件通知(Event Notification)方式:

讓我們用具體的例子來看一下。在下麵的例子中,有三個微服務,“Order Service”, “Customer Service” 和“Product Service”.

file

圖片來源

先說讀數據,假設要創建一個“Order”,在這個過程中需要讀取“Customer”的數據和“Product”數據。如果用事件通知的方式就只能在“Order Service”本地也創建只讀“Customer”和“Product”表,並把數據用消息的方式同步過來。

再說寫數據,如果在創建一個“Order”時需要創建一個新的“Customer”或要修改“Customer”的信息,那麼可以在界面上跳轉到用戶創建頁面,然後在“Customer Service”創建用戶之後再發”用戶已創建“的消息,“Order Service”接到消息,更新本地“Customer”表。

這並不是一個很好的使用事件驅動的例子,因為事件驅動的優點就是不同的程式之間可以獨立運行,沒有綁定關係。但現在“Order Service”需要等待“Customer Service”創建完了之後才能繼續運行,來完成整個創建“Order”的工作。主要是因為“Order”和“Customer”本身從邏輯上來講就是緊耦合關係,沒有“Customer”你是不能創建“Order”的。

在這種緊耦合的情況下,也可以使用RPC。你可以建立一個更高層級的管理程式來管理這些微服務之間的調用,這樣“Order Service”就不必直接調用“Customer Service”了。當然它從本質上來講並沒有解除耦合,只是把耦合轉移到了上一層,但至少現在“order Service”和“Customer Service”可以互不影響了。之所以不能根除這種緊耦合關係是因為它們在業務上是緊耦合的。

再舉一個購物的例子。用戶選好商品之後進行“Checkout”,生成“Order”,然後需要“payment”,再從“Inventory”取貨,最後由“Shipment”發貨,它們每一個都是微服務。這個例子用RPC方式和事件通知方式都可以完成。當用RPC方式時,由“Order”服務調用其他幾個服務來完成整個功能。用事件通知方式時,“Checkout”服務完成之後發送“Order Placed”消息,“Payment”服務收到消息,接收用戶付款,發送“Payment received”消息。“Inventory”服務收到消息,從倉庫里取貨,併發送“Goods fetched”消息。“Shipment”服務得到消息,發送貨物,併發送“Goods shipped”消息。

file

圖片來源

對這個例子來講,使用事件驅動是一個不錯的選擇,因為每個服務發消息之後它不需要任何反饋,這個消息由下一個模塊接收來完成下一步動作,時間上的要求也比上一個要寬鬆。用事件驅動的好處是降低了耦合度,壞處是你現在不能在程式里找到整個購物過程的步驟。如果一個業務邏輯有它自己相對固定的流程和步驟,那麼使用RPC或業務流程管理(BPM)能夠更方便地管理這些流程。在這種情況下選哪種方案呢?在我看來好處和壞處是大致相當的。從技術上來講要選事件驅動,從業務上來講要選RPC。不過現在越來越多的人採用事件通知作為微服務的集成方式,它似乎已經成了微服務之間的標椎調用方式。

事件溯源(Event Sourcing):

這是一種具有顛覆性質的的設計,它把系統中所有的數據都以事件(Event)的方式記錄下來,它的持久存儲叫Event Store, 一般是建立在資料庫或消息隊列(例如Kafka)基礎之上,並提供了對事件進行操作的介面,例如事件的讀寫和查詢。事件溯源是由領域驅動設計(Domain-Driven Design)提出來的。DDD中有一個很重要的概念,有界上下文(Bounded Context),可以用有界上下文來劃分微服務,每個有界上下文都可以是一個微服務。 下麵是有界上下文的示例。下圖中有兩個服務“Sales”和“Support”。有界上下文的一個關鍵是如何處理共用成員, 在圖中是“Customer”和“Product”。在不同的有界上下文中,共用成員的含義、用法以及他們的對象屬性都會有些不同,DDD建議這些共用成員在各自的有界上下文中都分別建自己的類(包括資料庫表),而不是共用。可以通過數據同步的手段來保持數據的一致性。下麵還會詳細講解。

file
圖片來源

事件溯源是微服務的一種存儲方式,它是微服務的內部實現細節。因此你可以決定哪些微服務採用事件溯源方式,哪些不採用,而不必所有的服務都變成事件溯源的。 通常整個應用程式只有一個Event Store, 不同的微服務都通過向Event Store發送和接受消息而互相通信。Event Store內部可以分成不同的stream(相當於消息隊列中的Topic), 供不同的微服務中的領域實體(Domain Entity)使用。

事件溯源的一個短板是數據查詢,它有兩種方式來解決。第一種是直接對stream進行查詢,這隻適合stream比較小並且查詢比較簡單的情況。查詢複雜的話,就要採用第二種方式,那就是建立一個只讀資料庫,把需要的數據放在庫中進行查詢。資料庫中的數據通過監聽Event Store中相關的事件來更新。

資料庫存儲方式只能保存當前狀態,而事件溯源則存儲了所有的歷史狀態,因而能根據需要回放到歷史上任何一點的狀態,具有很大優勢。但它也不是一點問題都沒有。第一,它的程式比較複雜,因為事件是一等公民,你必須把業務邏輯按照事件的方式整理出來,然後用事件來驅動程式。第二,如果你要想修改事件或事件的格式就比較麻煩,因為舊的事件已經存儲在Event Store里了(事件就像日誌,是只讀的),沒有辦法再改。

由於事件溯源和事件通知錶面上看起來很像,不少人都搞不清楚它們的區別。事件通知只是微服務的集成方式,程式內部是不使用事件溯源的,內部實現仍然是傳統的資料庫方式。只有當要與其他微服務集成時才會發消息。而在事件溯源中,事件是一等公民,可以不要資料庫,全部數據都是按照事件的方式存儲的。

雖然事件溯源的踐行者有不同的意見,但有不少人都認為事件溯源不是微服務的集成方式,而是微服務的一種內部實現方式。因此,在一個系統中,可以某些微服務用事件溯源,另外一些微服務用資料庫。當你要集成這些微服務時,你可以用事件通知的方式。註意現在有兩種不同的事件需要區分開,一種是微服務的內部事件,是顆粒度比較細的,這種事件只發送到這個微服務的stream中,只被事件溯源使用。另一種是其他微服務也關心的,是顆粒度比較粗的,這種事件會放到另外一個或幾個stream中,被多個微服務使用,是用來做服務之間集成的。這樣做的好處是限制了事件的作用範圍,減少了不相關事件對程式的干擾。詳見"Domain Events vs. Event Sourcing".

事件溯源出現已經很長時間了,雖然熱度一直在上升(尤其是這兩年),但總的來說非常緩慢,談論的人不少,但生產環境使用的不多。究其原因就是應為它對現在的體繫結構顛覆太大,需要更改數據存儲結構和程式的工作方式,還是有一定風險的。另外,微服務已經形成了一整套體系,從程式部署,服務發現與註冊,到監控,服務韌性(Service Resilience),它們基本上都是針對RPC的,雖然也支持消息,但成熟度就差多了,因此有不少工作還是要自己來做。有意思的是Kafka一直在推動它作為事件驅動的工具,也取得了很大的成功。但它卻沒有得到事件溯源圈內的認可(詳見這裡)。
多數事件溯源都使用一個叫evenstore的開源Event Store,或是基於某個資料庫的Event Store,只有比較少的人用Kafka做Event Store。 但如果用Kafka實現事件通知就一點問題都沒有。總的來說,對大多數公司來講事件溯源是有一定挑戰的,應用時需要找到合適的場景。如果你要嘗試的話,可以先拿一個微服務試水。

雖然現在事件驅動還有些生澀,但從長遠來講,還是很看好它的。像其他全新的技術一樣,事件溯源需要大規模的適用場景來推動。例如容器技術就是因為微服務的流行和推動,才走向主流。事件溯源以前的適用場景只限於記賬和源代碼庫,局限性較大。區塊鏈可能會成為它的下一個機遇,因為它用的也是事件溯源技術。另外AI今後會滲入到具體程式中,使程式具有學習功能。而RPC模式註定沒有自適應功能。事件驅動本身就具有對事件進行反應的能力,這是自我學習的基礎。因此,這項技術長遠來講定會大放異彩,但短期內(3-5年)大概不會成為主流。

RPC方式:

RPC的方式就是遠程函數調用,像RESTFul,gRPC, DUBBO 都是這種方式。它一般是同步的,可以馬上得到結果。在實際中,大多數應用都要求立刻得到結果,這時同步方式更有優勢,代碼也更簡單。

服務網關(API Gateway):

熟悉微服務的人可能都知道服務網關(API Gateway)。當UI需要調用很多微服務時,它需要瞭解每個服務的介面,這個工作量很大。於是就用服務網關創建了一個Facade,把幾個微服務封裝起來,這樣UI就只調用服務網關就可以了,不需要去對付每一個微服務。下麵是API Gateway示例圖:

file

圖片來源

服務網關(API Gateway)不是為瞭解決微服務之間調用的緊耦合問題,它主要是為了簡化客戶端的工作。其實它還可以用來降低函數之間的耦合度。 有了API Gateway之後,一旦服務介面修改,你可能只需要修改API Gateway, 而不必修改每個調用這個函數的客戶端,這樣就減少了程式的耦合性。

服務調用:

可以借鑒API Gateway的思路來減少RPC調用的耦合度,例如把多個微服務組織起來形成一個完整功能的服務組合,並對外提供統一的服務介面。這種想法跟上面的API Gateway有些相似,都是把服務集中起來提供粗顆粒(Coarse Granular)服務,而不是細顆粒的服務(Fine Granular)。但這樣建立的服務組合可能只適合一個程式使用,沒有多少共用價值。因此如果有合適的場景就採用,否側也不必強求。雖然我們不能降低RPC服務之間的耦合度,卻可以減少這種緊耦合帶來的影響。

降低緊耦合的影響:

什麼是緊耦合的主要問題呢?就是客戶端和服務端的升級不同步。服務端總是先升級,客戶端可能有很多,如果要求它們同時升級是不現實的。它們有各自的部署時間表,一般都會選擇在下一次部署時順帶升級。

一般有兩個辦法可以解決這個問題:

  1. 同時支持多個版本:這個工作量比較大,因此大多數公司都不會採用這種方式。
  2. 服務端向後相容:這是更通用的方式。例如你要加一個新功能或有些客戶要求給原來的函數增加一個新的參數,但別的客戶不需要這個參數。這時你只好新建一個函數,跟原來的功能差不多,只是多了一個參數。這樣新舊客戶的需求都能滿足。它的好處是向後相容(當然這取決於你使用的協議)。它的壞處是當以後新的客戶來了,看到兩個差不多的函數就糊塗了,不知道該用那個。而且時間越長越嚴重,你的服務端可能功能增加的不多,但相似的函數卻越來越多,無法選擇。

它的解決辦法就是使用一個支持向後相容的RPC協議,現在最好的就是Protobuf+gRPC,尤其是在向後相容上。它給每個服務定義了一個介面,這個介面是與編程語言無關的中性介面,然後你可以用工具生成各個語言的實現代碼,供不同語言使用。函數定義的變數都有編號,變數可以是可選類型的,這樣就比較好地解決了函數相容的問題。就用上面的例子,當你要增加一個可選參數時,你就定義一個新的可選變數。由於它是可選的,原來的客戶端不需要提供這個參數,因此不需要修改程式。而新的客戶端可以提供這個參數。你只要在服務端能同時處理這兩種情況就行了。這樣服務端並沒有增加新的函數,但用戶的新需求滿足了,而且還是向後相容的。

微服務的數量有沒有上限?

總的來說微服務的數量不要太多,不然會有比較重的運維負擔。有一點需要明確的是微服務的流行不是因為技術上的創新,而是為了滿足管理上的需要。單體程式大了之後,各個模塊的部署時間要求不同,對伺服器的優化要求也不同,而且團隊人數眾多,很難協調管理。把程式拆分成微服務之後,每個團隊負責幾個服務,就容易管理了,而且每個團隊也可以按照自己的節奏進行創新,但它給運維帶來了巨大的麻煩。所以在微服務剛出來時,我一直覺得它是一個退步,弊大於利。但由於管理上的問題沒有其他解決方案,只有硬著頭皮上了。值得慶幸的是微服務帶來的麻煩都是可解的。直到後來,微服務建立了全套的自動化體系,從程式集成到部署,從全鏈路跟蹤到日誌,以及服務檢測,服務發現和註冊,這樣才把微服務的工作量降了下來。雖然微服務在技術上一無是處,但它的流行還是大大推動了容器技術,服務網格(Service Mesh)和全鏈路跟蹤等新技術的發展。不過它本身在技術上還是沒有發現任何優勢。。直到有一天,我意識到單體程式其實性能調試是很困難的(很難分離出瓶頸點),而微服務配置了全鏈路跟蹤之後,能很快找到癥結所在。看來微服務從技術來講也不全是缺點,總算也有好的地方。但微服務的顆粒度不宜過細,否則工作量還是太大。

一般規模的公司十幾個或幾十個微服務都是可以承受的,但如果有幾百個甚至上千個,那麼絕不是一般公司可以管理的。儘管現有的工具已經很齊全了,而且與微服務有關的整個流程也已經基本上全部自動化了,但它還是會增加很多工作。Martin Fowler幾年以前建議先從單體程式開始(詳見 MonolithFirst),然後再逐步把功能拆分出去,變成一個個的微服務。但是後來有人反對這個建議,他也有些鬆口了。如果單體程式不是太大,這是個好主意。可以用數據額庫表的數量來衡量程式的大小,我見過大的單體程式有幾百張表,這就太多了,很難管理。正常情況下,一個微服務可以有兩、三張表到五、六張表,一般不超過十張表。但如果要減少微服務數量的話,可以把這個標準放寬到不要超過二十張表。用這個做為大致的指標來創建微程式,如果使用一段時間之後還是覺得太大了,那麼再逐漸拆分。當然,按照這個標準建立的服務更像是服務組合,而不是單個的微服務。不過它會為你減少工作量。只要不影響業務部門的創新進度,這是一個不錯的方案。

到底應不應該選擇微服務呢?如果單體程式已經沒法管理了,那麼你別無選擇。如果沒有管理上的問題,那麼微服務帶給你的只有問題和麻煩。其實,一般公司都沒有太多選擇,只能採用微服務,不過你可以選擇建立比較少的微服務。如果還是沒法決定,有一個折中的方案,“內部微服務設計”。

內部微服務設計:

這種設計錶面上看起來是一個單體程式,它只有一個源代碼存儲倉庫,一個資料庫,一個部署,但在程式內部可以按照微服務的思想來進行設計。它可以分成多個模塊,每個模塊是一個微服務,可以由不同的團隊管理。

file

圖片來源

用這張圖做例子。這個圖裡的每個圓角方塊大致是一個微服務,但我們可以把它作為一個單體程式來設計,內部有五個微服務。每個模塊都有自己的資料庫表,它們都在一個資料庫中,但模塊之間不能跨資料庫訪問(不要建立模塊之間資料庫表的外鍵)。“User”(在Conference Management模塊中)是一個共用的類,但在不同的模塊中的名字不同,含義和用法也不同,成員也不一樣(例如,在“Customer Service”里叫“Customer”)。DDD(Domain-Driven Design)建議不要共用這個類,而是在每一個有界上下文(模塊)中都建一個新類,並擁有新的名字。雖然它們的資料庫中的數據應該大致相同,但DDD建議每一個有界上下文中都建一個新表,它們之間再進行數據同步。

這個所謂的“內部微服務設計”其實就是DDD,但當時還沒有微服務,因此外表看起來是單體程式,但內部已經是微服務的設計了。它的書在2003就出版了,當時就很有名。但它更偏重於業務邏輯的設計,踐行起來也比較困難,因此大家談論得很多,真正用的較少。直到十年之後,微服務出來之後,人們發現它其實內部就是微服務,而且微服務的設計需要用它的思想來指導,於是就又重新煥發了青春,而且這次更猛,已經到了每個談論微服務的人都不得不談論DDD的地步。不過一本軟體書籍,在十年之後還能指導新技術的設計,非常令人欽佩。

這樣設計的好處是它是一個單體程式,省去了多個微服務帶來的部署、運維的麻煩。但它內部是按微服務設計的,如果以後要拆分成微服務會比較容易。至於什麼時候拆分不是一個技術問題。如果負責這個單體程式的各個團隊之間不能在部署時間表,伺服器優化等方面達成一致,那麼就需要拆分了。當然你也要應對隨之而來的各種運維麻煩。內部微服務設計是一個折中的方案,如果你想試水微服務,但又不願意冒太大風險時,這是一個不錯的選擇。

結論:

微服務之間的調用有兩種方式,RPC和事件驅動。事件驅動是更好的方式,因為它是松耦合的。但如果業務邏輯是緊耦合的,RPC方式也是可行的(它的好處是代碼更簡單),而且你還可以通過選取合適的協議(Protobuf+gRPC)來降低這種緊耦合帶來的危害。由於事件溯源和事件通知的相似性,很多人把兩者弄混了,但它們實際上是完全不同的東西。微服務的數量不宜太多,可以先創建比較大的微服務(更像是服務組合)。如果你還是不能確定是否採用微服務架構,可以先從“內部微服務設計”開始,再逐漸拆分。

索引:

[1] What do you mean by “Event-Driven”
https://martinfowler.com/articles/201701-event-driven.html

[2] Domain-Driven Design
https://dddcommunity.org/book/evans_2003/

[3] BoundedContext
https://martinfowler.com/bliki/BoundedContext.html

[4] Domain Events vs. Event Sourcing
https://www.innoq.com/en/blog/domain-events-versus-event-sourcing/

[5] Using Kafka as a (CQRS) Eventstore. Good idea?
https://stackoverflow.com/a/49868866

[6] Evenstore
https://eventstore.org/

[7] MonolithFirst
https://martinfowler.com/bliki/MonolithFirst.html


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

-Advertisement-
Play Games
更多相關文章
  • 1、不同視口的獲取方法 2、JavaScript檢測橫豎屏 3、CSS檢測橫豎屏 4、meta標簽屬性設置 5、meta標簽屬性設置設置劉海屏&底部小黑條 設置安全區域與邊界的距離 註:constant函數在iOS=11.2時生效 ...
  • jQuery API及用法總結 選擇器 基本選擇器 1. \ 通用選擇器 2. .class 類選擇器,一個元素可以有多個類(chrome使用原生js函數getElementByClassName()實現) 利用類選擇器改變元素的樣式 3. element元素選擇器,DOM節點的標簽名(調用函數ge ...
  • 在js和jquery使用中,經常使用到頁面載入完成後執行某一方法。通過整理,大概是五種方式(其中有的只是書寫方式不一樣)。 1:使用jQuery的$(function){}; 2:使用jquery的$(document).ready(function(){}); 前兩者本質上沒有區別,第1種是第2種 ...
  • 場景 Docker Compose部署GitLab服務,搭建自己的代碼托管平臺(圖文教程): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/101039801 從零開始一步一步搭建Ubuntu Server伺服器、修改數據源、安裝 ...
  • 場景 Docker Compose部署GitLab服務,搭建自己的代碼托管平臺(圖文教程): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/101039801 從零開始一步一步搭建Ubuntu Server伺服器、修改數據源、安裝 ...
  • 場景 Docker Compose部署GitLab服務,搭建自己的代碼托管平臺(圖文教程): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/101039801 從零開始一步一步搭建Ubuntu Server伺服器、修改數據源、安裝 ...
  • Redis主從複製機制 1、讀寫分離的好處 + 性能優化:主伺服器專註於寫操作,可以更適合寫入數據的模式工作;同樣,從伺服器專註於讀操作,可以用更適合讀取數據的模式工作。 + 強化數據安全,避免單點故障:由於同步機制的存在,各個伺服器之間的數據保持一致,所以其中某個伺服器宕機不會導致數據丟失或無法訪 ...
  • UML是一種統一建模語言,他是以面向對象的方式來實現對任何的系統進行描述的一種語言, 它包括9種圖形+包圖,分為靜態和動態兩種,也就是結構圖和行為圖 “靜態”圖有:用例圖、類圖、對象圖、部署圖、構件圖 “動態”圖有:序列圖、活動圖、狀態圖和協作圖。 1、用例圖: 用例圖是一種從用戶角度來描述系統功能 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...