這就是大名鼎鼎的Netty, Hadoop、Dubbo都用了

来源:https://www.cnblogs.com/dongguangming/archive/2020/04/02/12617190.html
-Advertisement-
Play Games

1. Netty 基礎 Netty 是一個高性能、非同步事件驅動的 NIO 框架,它提供了對 TCP、UDP 和文件傳輸的支持,作為一個非同步 NIO 框架,Netty 的所有 IO 操作都是非同步非阻塞的,通過 Future-Listener 機制,用戶可以方便的主動獲取或者通過通知機制獲得 IO 操作 ...


 

1. Netty 基礎

        Netty 是一個高性能、非同步事件驅動的 NIO 框架,它提供了對 TCP、UDP 和文件傳輸的支持,作為一個非同步 NIO 框架,Netty 的所有 IO 操作都是非同步非阻塞的,通過 Future-Listener 機制,用戶可以方便的主動獲取或者通過通知機制獲得 IO 操作結果。它是一個網路應用框架。

2. Netty 高性能之道

2.1. RPC 調用的性能模型分析

2.1.1. 傳統 RPC 調用性能差的三宗罪

網路傳輸方式問題:傳統的 RPC 框架或者基於 RMI 等方式的遠程服務(過程)調用採用了同步阻塞 IO,當客戶端的併發壓力或者網路時延增大之後,同步阻塞 IO 會由於頻繁的 wait 導致 IO 線程經常性的阻塞,由於線程無法高效的工作,IO 處理能力自然下降。

下麵,我們通過 BIO 通信模型圖看下 BIO 通信的弊端:

圖2-1 BIO 通信模型圖

採用 BIO 通信模型的服務端,通常由一個獨立的 Acceptor 線程負責監聽客戶端的連接,接收到客戶端連接之後為客戶端連接創建一個新的線程處理請求消息,處理完成之後,返回應答消息給客戶端,線程銷毀,這就是典型的一請求一應答模型。該架構最大的問題就是不具備彈性伸縮能力,當併發訪問量增加後,服務端的線程個數和併發訪問數成線性正比,由於線程是 JAVA 虛擬機非常寶貴的系統資源,當線程數膨脹之後,系統的性能急劇下降,隨著併發量的繼續增加,可能會發生句柄溢出、線程堆棧溢出等問題,並導致伺服器最終宕機。

序列化方式問題:Java 序列化存在如下幾個典型問題:

1) Java 序列化機制是 Java 內部的一種對象編解碼技術,無法跨語言使用;例如對於異構系統之間的對接,Java 序列化後的碼流需要能夠通過其它語言反序列化成原始對象(副本),目前很難支持;

2) 相比於其它開源的序列化框架,Java 序列化後的碼流太大,無論是網路傳輸還是持久化到磁碟,都會導致額外的資源占用;

3) 序列化性能差(CPU 資源占用高)。

線程模型問題:由於採用同步阻塞 IO,這會導致每個 TCP 連接都占用1個線程,由於線程資源是 JVM 虛擬機非常寶貴的資源,當 IO 讀寫阻塞導致線程無法及時釋放時,會導致系統性能急劇下降,嚴重的甚至會導致虛擬機無法創建新的線程。

2.1.2. 高性能的三個主題

1) 傳輸:用什麼樣的通道將數據發送給對方,BIO、NIO 或者 AIO,IO 模型在很大程度上決定了框架的性能。

2) 協議:採用什麼樣的通信協議,HTTP 或者內部私有協議。協議的選擇不同,性能模型也不同。相比於公有協議,內部私有協議的性能通常可以被設計的更優。

3) 線程:數據報如何讀取?讀取之後的編解碼在哪個線程進行,編解碼後的消息如何派發, Reactor 線程模型的不同,對性能的影響也非常大。

圖2-2 RPC 調用性能三要素

2.2. Netty 高性能之道

2.2.1. 非同步非阻塞通信

在 IO 編程過程中,當需要同時處理多個客戶端接入請求時,可以利用多線程或者 IO 多路復用技術進行處理。IO 多路復用技術通過把多個 IO 的阻塞復用到同一個 select 的阻塞上,從而使得系統在單線程的情況下可以同時處理多個客戶端請求。與傳統的多線程/多進程模型比,I/O 多路復用的最大優勢是系統開銷小,系統不需要創建新的額外進程或者線程,也不需要維護這些進程和線程的運行,降低了系統的維護工作量,節省了系統資源。

JDK1.4 提供了對非阻塞 IO(NIO)的支持,JDK1.5_update10 版本使用 epoll 替代了傳統的 select/poll,極大的提升了 NIO 通信的性能。

JDK NIO 通信模型如下所示:

圖2-3 NIO 的多路復用模型圖

與 Socket 類和 ServerSocket 類相對應,NIO 也提供了 SocketChannel 和 ServerSocketChannel 兩種不同的套接字通道實現。這兩種新增的通道都支持阻塞和非阻塞兩種模式。阻塞模式使用非常簡單,但是性能和可靠性都不好,非阻塞模式正好相反。開發人員一般可以根據自己的需要來選擇合適的模式,一般來說,低負載、低併發的應用程式可以選擇同步阻塞 IO 以降低編程複雜度。但是對於高負載、高併發的網路應用,需要使用 NIO 的非阻塞模式進行開發。

Netty 架構按照 Reactor 模式設計和實現,它的服務端通信序列圖如下:

圖2-3 NIO 服務端通信序列圖

客戶端通信序列圖如下:

圖2-4 NIO 客戶端通信序列圖

Netty 的 IO 線程 NioEventLoop 由於聚合了多路復用器 Selector,可以同時併發處理成百上千個客戶端 Channel,由於讀寫操作都是非阻塞的,這就可以充分提升 IO 線程的運行效率,避免由於頻繁 IO 阻塞導致的線程掛起。另外,由於 Netty 採用了非同步通信模式,一個 IO 線程可以併發處理 N 個客戶端連接和讀寫操作,這從根本上解決了傳統同步阻塞 IO 一連接一線程模型,架構的性能、彈性伸縮能力和可靠性都得到了極大的提升。

2.2.2. 零拷貝技術

很多用戶都聽說過 Netty 具有“零拷貝”功能,但是具體體現在哪裡又說不清楚,本小節就詳細對 Netty 的“零拷貝”功能進行講解。

Netty 的“零拷貝”主要體現在如下三個方面:

1) Netty 的接收和發送 ByteBuffer 採用 DIRECT BUFFERS,使用堆外直接記憶體進行 Socket 讀寫,不需要進行位元組緩衝區的二次拷貝。如果使用傳統的堆記憶體(HEAP BUFFERS)進行 Socket 讀寫,JVM 會將堆記憶體 Buffer 拷貝一份到直接記憶體中,然後才寫入 Socket 中。相比於堆外直接記憶體,消息在發送過程中多了一次緩衝區的記憶體拷貝。

2) Netty 提供了組合 Buffer 對象,可以聚合多個 ByteBuffer 對象,用戶可以像操作一個 Buffer 那樣方便的對組合 Buffer 進行操作,避免了傳統通過記憶體拷貝的方式將幾個小 Buffer 合併成一個大的 Buffer。

3) Netty 的文件傳輸採用了 transferTo 方法,它可以直接將文件緩衝區的數據發送到目標 Channel,避免了傳統通過迴圈 write 方式導致的記憶體拷貝問題。

下麵,我們對上述三種“零拷貝”進行說明,先看 Netty 接收 Buffer 的創建:

圖2-5 非同步消息讀取“零拷貝”

每迴圈讀取一次消息,就通過 ByteBufAllocator的ioBuffer 方法獲取 ByteBuf 對象,下麵繼續看它的介面定義:

圖2-6 ByteBufAllocator 通過 ioBuffer 分配堆外記憶體

當進行 Socket IO 讀寫的時候,為了避免從堆記憶體拷貝一份副本到直接記憶體,Netty 的 ByteBuf 分配器直接創建非堆記憶體避免緩衝區的二次拷貝,通過“零拷貝”來提升讀寫性能。

下麵我們繼續看第二種“零拷貝”的實現 CompositeByteBuf,它對外將多個 ByteBuf 封裝成一個 ByteBuf,對外提供統一封裝後的 ByteBuf 介面,它的類定義如下:

圖2-7 CompositeByteBuf 類繼承關係

通過繼承關係我們可以看出 CompositeByteBuf 實際就是個 ByteBuf 的包裝器,它將多個 ByteBuf 組合成一個集合,然後對外提供統一的 ByteBuf 介面,相關定義如下:

圖2-8 CompositeByteBuf 類定義

添加 ByteBuf,不需要做記憶體拷貝,相關代碼如下:

圖2-9 新增 ByteBuf 的“零拷貝”

最後,我們看下文件傳輸的“零拷貝”:

圖2-10 文件傳輸“零拷貝”

Netty 文件傳輸 DefaultFileRegion 通過 transferTo 方法將文件發送到目標 Channel 中,下麵重點看 FileChannel 的 transferTo 方法,它的 API DOC 說明如下:

圖2-11 文件傳輸 “零拷貝”

對於很多操作系統它直接將文件緩衝區的內容發送到目標 Channel 中,而不需要通過拷貝的方式,這是一種更加高效的傳輸方式,它實現了文件傳輸的“零拷貝”。

2.2.3. 記憶體池

隨著 JVM 虛擬機和 JIT 即時編譯技術的發展,對象的分配和回收是個非常輕量級的工作。但是對於緩衝區 Buffer,情況卻稍有不同,特別是對於堆外直接記憶體的分配和回收,是一件耗時的操作。為了儘量重用緩衝區,Netty 提供了基於記憶體池的緩衝區重用機制。下麵我們一起看下 Netty ByteBuf 的實現:

圖2-12 記憶體池 ByteBuf

Netty 提供了多種記憶體管理策略,通過在啟動輔助類中配置相關參數,可以實現差異化的定製。

下麵通過性能測試,我們看下基於記憶體池迴圈利用的 ByteBuf 和普通 ByteBuf 的性能差異。

用例一,使用記憶體池分配器創建直接記憶體緩衝區:

圖2-13 基於記憶體池的非堆記憶體緩衝區測試用例

用例二,使用非堆記憶體分配器創建的直接記憶體緩衝區:

圖2-14 基於非記憶體池創建的非堆記憶體緩衝區測試用例

各執行300萬次,性能對比結果如下所示:

圖2-15 記憶體池和非記憶體池緩衝區寫入性能對比

性能測試表明,採用記憶體池的 ByteBuf 相比於朝生夕滅的 ByteBuf,性能高23倍左右(性能數據與使用場景強相關)。

下麵我們一起簡單分析下 Netty 記憶體池的記憶體分配:

圖2-16 AbstractByteBufAllocator 的緩衝區分配

繼續看 newDirectBuffer 方法,我們發現它是一個抽象方法,由 AbstractByteBufAllocator 的子類負責具體實現,代碼如下:

圖2-17 newDirectBuffer 的不同實現

代碼跳轉到 PooledByteBufAllocator 的 newDirectBuffer 方法,從 Cache 中獲取記憶體區域 PoolArena,調用它的 allocate 方法進行記憶體分配:

圖2-18 PooledByteBufAllocator 的記憶體分配

PoolArena 的 allocate 方法如下:

圖2-18 PoolArena 的緩衝區分配

我們重點分析 newByteBuf 的實現,它同樣是個抽象方法,由子類 DirectArena 和 HeapArena 來實現不同類型的緩衝區分配,由於測試用例使用的是堆外記憶體,

圖2-19 PoolArena 的 newByteBuf 抽象方法

因此重點分析 DirectArena 的實現:如果沒有開啟使用 sun 的 unsafe,則

圖2-20 DirectArena 的 newByteBuf 方法實現

執行 PooledDirectByteBuf 的 newInstance 方法,代碼如下:

圖2-21 PooledDirectByteBuf 的 newInstance 方法實現

通過 RECYCLER 的 get 方法迴圈使用 ByteBuf 對象,如果是非記憶體池實現,則直接創建一個新的 ByteBuf 對象。從緩衝池中獲取 ByteBuf 之後,調用 AbstractReferenceCountedByteBuf的setRefCnt 方法設置引用計數器,用於對象的引用計數和記憶體回收(類似 JVM 垃圾回收機制)。

2.2.4. 高效的 Reactor 線程模型(重點

常用的 Reactor 線程模型有三種,分別如下:

1) Reactor 單線程模型;

2) Reactor 多線程模型;

3) 主從 Reactor 多線程模型(很重點

Reactor 單線程模型,指的是所有的 IO 操作都在同一個 NIO 線程上面完成,NIO 線程的職責如下:

1) 作為 NIO 服務端,接收客戶端的 TCP 連接;

2) 作為 NIO 客戶端,向服務端發起 TCP 連接;

3) 讀取通信對端的請求或者應答消息;

4) 向通信對端發送消息請求或者應答消息。

Reactor 單線程模型示意圖如下所示:

圖2-22 Reactor 單線程模型

由於 Reactor 模式使用的是非同步非阻塞 IO,所有的 IO 操作都不會導致阻塞,理論上一個線程可以獨立處理所有 IO 相關的操作。從架構層面看,一個 NIO 線程確實可以完成其承擔的職責。例如,通過 Acceptor 接收客戶端的 TCP 連接請求消息,鏈路建立成功之後,通過 Dispatch 將對應的 ByteBuffer 派發到指定的 Handler 上進行消息解碼。用戶 Handler 可以通過 NIO 線程將消息發送給客戶端。

對於一些小容量應用場景,可以使用單線程模型。但是對於高負載、大併發的應用卻不合適,主要原因如下:

1) 一個 NIO 線程同時處理成百上千的鏈路,性能上無法支撐,即便 NIO 線程的 CPU 負荷達到100%,也無法滿足海量消息的編碼、解碼、讀取和發送;

2) 當 NIO 線程負載過重之後,處理速度將變慢,這會導致大量客戶端連接超時,超時之後往往會進行重發,這更加重了 NIO 線程的負載,最終會導致大量消息積壓和處理超時,NIO 線程會成為系統的性能瓶頸;

3) 可靠性問題:一旦 NIO 線程意外跑飛,或者進入死迴圈,會導致整個系統通信模塊不可用,不能接收和處理外部消息,造成節點故障。

為瞭解決這些問題,演進出了 Reactor 多線程模型,下麵我們一起學習下 Reactor 多線程模型。

Rector 多線程模型與單線程模型最大的區別就是有一組 NIO 線程處理 IO 操作,它的原理圖如下:

圖2-23 Reactor 多線程模型

Reactor 多線程模型的特點:

1) 有專門一個 NIO 線程-Acceptor 線程用於監聽服務端,接收客戶端的 TCP 連接請求;

2) 網路 IO 操作-讀、寫等由一個 NIO 線程池負責,線程池可以採用標準的 JDK 線程池實現,它包含一個任務隊列和 N 個可用的線程,由這些 NIO 線程負責消息的讀取、解碼、編碼和發送;

3) 1個 NIO 線程可以同時處理 N 條鏈路,但是1個鏈路只對應1個 NIO 線程,防止發生併發操作問題。

在絕大多數場景下,Reactor 多線程模型都可以滿足性能需求;但是,在極特殊應用場景中,一個 NIO 線程負責監聽和處理所有的客戶端連接可能會存在性能問題。例如百萬客戶端併發連接,或者服務端需要對客戶端的握手消息進行安全認證,認證本身非常損耗性能。在這類場景下,單獨一個 Acceptor 線程可能會存在性能不足問題,為瞭解決性能問題,產生了第三種 Reactor 線程模型-主從 Reactor 多線程模型。

主從 Reactor 線程模型的特點是:服務端用於接收客戶端連接的不再是個1個單獨的 NIO 線程,而是一個獨立的 NIO 線程池。Acceptor 接收到客戶端 TCP 連接請求處理完成後(可能包含接入認證等),將新創建的 SocketChannel 註冊到 IO 線程池(sub reactor 線程池)的某個 IO 線程上,由它負責 SocketChannel 的讀寫和編解碼工作。Acceptor 線程池僅僅只用於客戶端的登陸、握手和安全認證,一旦鏈路建立成功,就將鏈路註冊到後端 subReactor 線程池的 IO 線程上,由 IO 線程負責後續的 IO 操作。

它的線程模型如下圖所示:

圖2-24 Reactor 主從多線程模型

利用主從 NIO 線程模型,可以解決1個服務端監聽線程無法有效處理所有客戶端連接的性能不足問題。因此,在 Netty 的官方 demo 中,推薦使用該線程模型。

事實上,Netty 的線程模型並非固定不變,通過在啟動輔助類中創建不同的 EventLoopGroup 實例並通過適當的參數配置,就可以支持上述三種 Reactor 線程模型。正是因為 Netty 對 Reactor 線程模型的支持提供了靈活的定製能力,所以可以滿足不同業務場景的性能訴求。

2.2.5. 無鎖化的串列設計理念

在大多數場景下,並行多線程處理可以提升系統的併發性能。但是,如果對於共用資源的併發訪問處理不當,會帶來嚴重的鎖競爭,這最終會導致性能的下降。為了儘可能的避免鎖競爭帶來的性能損耗,可以通過串列化設計,即消息的處理儘可能在同一個線程內完成,期間不進行線程切換,這樣就避免了多線程競爭和同步鎖。

為了儘可能提升性能,Netty 採用了串列無鎖化設計,在 IO 線程內部進行串列操作,避免多線程競爭導致的性能下降。錶面上看,串列化設計似乎 CPU 利用率不高,併發程度不夠。但是,通過調整 NIO 線程池的線程參數,可以同時啟動多個串列化的線程並行運行,這種局部無鎖化的串列線程設計相比一個隊列-多個工作線程模型性能更優。

Netty 的串列化設計工作原理圖如下:

圖2-25 Netty 串列化工作原理圖

Netty 的 NioEventLoop 讀取到消息之後,直接調用 ChannelPipeline 的 fireChannelRead(Object msg),只要用戶不主動切換線程,一直會由 NioEventLoop 調用到用戶的 Handler,期間不進行線程切換,這種串列化處理方式避免了多線程操作導致的鎖的競爭,從性能角度看是最優的。

2.2.6 靈活的 TCP 參數配置能力

合理設置 TCP 參數在某些場景下對於性能的提升可以起到顯著的效果,例如 SO_RCVBUF 和 SO_SNDBUF。如果設置不當,對性能的影響是非常大的。下麵我們總結下對性能影響比較大的幾個配置項:

1) SO_RCVBUF 和 SO_SNDBUF:通常建議值為 128 K 或者 256 K;

2) SO_TCPNODELAY:NAGLE 演算法通過將緩衝區內的小封包自動相連,組成較大的封包,阻止大量小封包的發送阻塞網路,從而提高網路應用效率。但是對於時延敏感的應用場景需要關閉該優化演算法;

3) 軟中斷:如果 Linux 內核版本支持 RPS(2.6.35以上版本),開啟 RPS 後可以實現軟中斷,提升網路吞吐量。RPS 根據數據包的源地址,目的地址以及目的和源埠,計算出一個 hash值,然後根據這個 hash 值來選擇軟中斷運行的 cpu,從上層來看,也就是說將每個連接和 cpu 綁定,並通過這個 hash 值,來均衡軟中斷在多個 cpu 上,提升網路並行處理性能。

Netty 在啟動輔助類中可以靈活的配置 TCP 參數,滿足不同的用戶場景。相關配置介面定義如下:

圖2-27 Netty 的 TCP 參數配置定義

2.3. 總結

通過對 Netty 的架構和性能模型進行分析,我們發現 Netty 架構的高性能是被精心設計和實現的,得益於高質量的架構和代碼,Netty 支持 10W TPS 的跨節點服務調用並不是件十分困難的事情。


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

-Advertisement-
Play Games
更多相關文章
  • 前面業務里有個搜索功能 , 入口比較深 , 現在想要把入口挪到有公共header的地方 , 在不想完全實現一遍功能的情況下 , 就需要模擬進行多個點擊事件來執行點擊後的效果 執行先點擊1 ,再給inout賦值 ,再點擊2 基本思路是類似jquery的trigger方法 , 原生js也是可以實現 , ...
  • 1 完整代碼下載 https://pan.baidu.com/s/1JJyVcP2KqXsd5G6eaYpgHQ 提取碼 3fzt (壓縮包名: 2020-3-24-demo.zip) 2 圖片展示 3 主要代碼 布爾運算後的物體的幾何體會自動 導入到 幾何體列表選項中, 可自由選配材質 紋理 挺簡 ...
  • 篩選組件包含一個 button 和一個 form,button 能控制 form 的顯示與隱藏。設計里 button 和 form 在一行,實現時理所當然地把這一行封裝成了一個組件。但在另一個項目里,設計有區別,button 被放到了面板的右上角,之前寫的組件沒法復用了。 ...
  • 網上統計數據,上海Web前端開發工程師這一職位的月平均收入為1.5萬元,工作經驗達到3年的web前端工程師甚至達到3萬元。 而且Web前端工程師一般工作1年左右,年薪一般就都能有15W,工作5年以上的通常能成為互聯網公司技術總監或產品經理,年薪達到25W左右。 前端工程師發展路徑: 工作1~2 年後 ...
  • JavaScript 操作 DOM 時經常會用到一些尺寸,本文介紹怪異模式和標準模式下的滾動條距離、視窗尺寸、文檔尺寸、元素文檔坐標的相容性寫法以及視窗滾動到指定位置的方法 ...
  • 內容中的{{var}}會直接顯示,使用過濾器:{{var | 過濾器名}},會先用過濾器處理var,再顯示。 按作用域劃分,有2種過濾器:全局過濾器、組件內過濾器。 demo 組件內過濾器 <div id="app"> <input v-model="content" /><br /> <!--綁定 ...
  • Netty是Trustin Lee在2004年開發的一款高性能的網路應用程式框架。相比於JDK自帶的NIO,Netty做了相當多的增強,且隔離了jdk nio的實現細節,API也比較友好,還支持流量整形等高級特性。在我們常見的一些開源項目中已經普遍的應用到了Netty,比如Dubbo、Elastic ...
  • 物聯網mqtt協議是可以發佈和訂閱通過java就可以實現 話不多說,mqtt,載入pom.xml文件格式 1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema- ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...