<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          ASP.NET服務 9個性能優(yōu)化技巧!

          共 5348字,需瀏覽 11分鐘

           ·

          2021-06-19 18:59

          理理Asp.net性能相關的問題及注意事項。

          以下這些內(nèi)容,全部是經(jīng)驗之談。如果你有別的建議,也可以從后臺發(fā)給我。

          服務器性能問題,通常在數(shù)據(jù)少的時候不會顯現(xiàn),也無需太多關注。但一旦數(shù)據(jù)量大了,就會變成一個麻煩且必須處理的事。

          通常,性能問題可能有許多不同的原因。內(nèi)存問題、緩慢的數(shù)據(jù)庫請求和太少的機器只是其中的一部分。手上的項目,每天10億級的數(shù)量量,在最近一個時間段,填了很多坑,也學到了不少東西。

          今天這個文章,我會把這一段的體會,總結成幾大類問題。當然,分類不一定很嚴謹,重要的是能給到大家一些建議,真到用時,能少刨一些坑,就夠了。另外,次序也不重要,我是想到哪些到哪的,并不是說前邊的內(nèi)容就比后面的內(nèi)容更需要注意。

          1. 數(shù)據(jù)庫調(diào)用

          數(shù)據(jù)庫調(diào)用的性能,會嚴重影響系統(tǒng)整體的性能。大多數(shù)情況下,與數(shù)據(jù)庫快速交互是獲得良好性能的最重要的因素。

          以下幾個點需要重點關注:

          • 索引策略

          索引對數(shù)據(jù)庫交互的影響不需要解釋。重要的是檢查,檢查每一個索引,和每一個查詢語句。很多時候,你以為的未必是你以為的。檢查查詢語句和條件對索引的使用,檢查索引的結構。要確保每個查詢語句,能正確使用你所希望使用的索引。

          • 表結構設計

          表結構設計最重要的,是對業(yè)務的理解。對數(shù)據(jù)之間的關系理解越深,表結構越趨于合理。

          • 同樣的工作,盡可能在數(shù)據(jù)庫上完成,避免在服務器中完成

          這個話不太好理解,用代碼舉個例子:

          // 好的方式
          var girls = dbContext.Users.Where(user => user.gender == female);
          var count = girls.Count();

          // 不好的方式
          var girls = dbContext.Users.Where(user => user.gender == female).ToList();
          var count = girls.Count;

          下邊這種方式,第一行以ToList()結束。當實體執(zhí)行查詢時,會從數(shù)據(jù)庫中檢索并獲取全部數(shù)據(jù),然后在服務器中進行計數(shù)。而上面的方式,會在數(shù)據(jù)庫中直接計數(shù)。很顯而易見的,數(shù)據(jù)庫中執(zhí)行計數(shù),網(wǎng)絡傳輸?shù)拇鷥r會更少。

          • 盡可能讓數(shù)據(jù)庫離應用服務器"近"點

          數(shù)據(jù)庫到應用服務器之間,無非是網(wǎng)絡。更"近"的網(wǎng)絡,會帶來更少的延時。這個"近"說的是網(wǎng)絡拓撲上的近,不是位置和距離。對于多機房分布式的應用,起碼的要求是讓一個或幾個完整的副本集與應用服務處于同一個數(shù)據(jù)中心。

          • 用數(shù)據(jù)庫希望的方式使用數(shù)據(jù)庫

          數(shù)據(jù)庫有很多種,關系型、NoSQL、內(nèi)存數(shù)據(jù)庫,等等。并不是所有的數(shù)據(jù)庫都一樣。有些適合Key-Value鍵值對,有些適合事務處理,有些適合存儲日志。

          在開發(fā)中,不要拘泥于數(shù)據(jù)庫類型,而應該根據(jù)業(yè)務類型和數(shù)據(jù)庫特性進行使用。比方說,MongoDB,本身是基于文檔的數(shù)據(jù)庫,結構上很不適合JOIN操作。但它非常適合存儲包含大量業(yè)務數(shù)據(jù)的文檔。所以,使用時要避免使用JOIN操作的業(yè)務。當然,這只是個例子。事實上MongoDB對于類似JOIN的內(nèi)容,有更好的處理模式,這個大家可以自行了解。

          • 保證數(shù)據(jù)庫有足夠的硬件資源

          服務器的伸縮一般提的比較高,但其實數(shù)據(jù)庫的伸縮性也需要非常重視。數(shù)據(jù)庫服務器,要關注到存儲空間、內(nèi)存、網(wǎng)絡和CPU。經(jīng)驗中,接近極限時,服務器未必會有明確的警報給你;而等到有警報出現(xiàn)時,恐怕已經(jīng)到達極限并發(fā)生了故障,就非常難于處理了。

          所以,當發(fā)現(xiàn)某些任務開始變慢,就意味著需要全面檢查了。

          • 承認某些低效查詢的存在

          不是所有的查詢都可以做到高效。尤其查詢是基于某些實體框架,例如EF或Hibernate。在技術和時間可能的情況下,少用數(shù)據(jù)框架是個好習慣。

          • 使用連接池,而不是單個連接

          如果每個查詢都需要重新建立連接,那是非常可怕的,從性能到應用的可靠性。使用數(shù)據(jù)庫,第一件事就是學會如何使用連接池。

          • 小心使用存儲過程

          當有需要花費大量時間的復雜查詢需要處理時,存儲過程是個解決方案。但一定要小心,一定要小心,一定要小心,重要的事情說三遍。

          在我的團隊中,存儲過程是被禁止使用的。相對來說,這兒安全的要求超過性能。

          不過,在這個文章中,尤其在討論數(shù)據(jù)庫操作的性能時,咱還是不能忘了存儲過程。

          • 數(shù)據(jù)庫分片策略

          分布式數(shù)據(jù)庫性能的核心在于分片。分片就一個原則:讓業(yè)務的每一個查詢操作,對應盡可能少的分片。

          ?

          上面寫的,其實是一些原則。實際上,最難的部分是確定這些問題。所以,需要對各種工具都熟悉。通常,數(shù)據(jù)庫本身也能提供相關內(nèi)容,例如慢查詢、擴展問題、網(wǎng)絡瓶頸等。對于數(shù)據(jù)庫,不要僅限于使用,一定深度的了解會對成長有相當?shù)膸椭?/p>

          2. 內(nèi)存壓力

          對于某些高吞吐量的應用,服務器的內(nèi)存壓力是最常見的問題。

          當吞吐量非常大的時候,垃圾回收(GC)會跟不上內(nèi)存的分配和釋放。而且這種壓力的體現(xiàn),是服務器在垃圾回收上花費的時間更多,而執(zhí)行代碼的時間更少。

          這種狀態(tài)在多種情況下都可能發(fā)生。最常見的情況是內(nèi)存容量耗盡。當您達到內(nèi)存極限時,垃圾回收器將出現(xiàn)恐慌,并啟動更頻繁的整體垃圾回收,而這種模式的回收代價非常大。但問題是,為什么會發(fā)生這種情況?為什么你內(nèi)存使用接近極限了?原因通常是錯誤或不太好的緩存管理或內(nèi)存泄漏。通過捕獲內(nèi)存快照并檢查是什么占用了所有字節(jié),可以很容易地用內(nèi)存分析器發(fā)現(xiàn)這一點。

          重要的是首先要意識到你有內(nèi)存問題。最簡單的方法是使用性能計數(shù)器。

          3. 緩存數(shù)據(jù)

          緩存可以是一個非常好、非常有效的優(yōu)化技術。典型的例子是,當客戶端發(fā)送請求時,服務器可以將結果保存在緩存中。當客戶端再次發(fā)送相同的請求(不一定是同一個客戶端)時,服務器不需要再次查詢數(shù)據(jù)庫或進行任何計算來獲得結果,而只是從緩存中獲取它。

          考慮一下搜索引擎的做法。如果這是一個常見的搜索,它可能會被要求每天多次。如果不做緩存,每次都使用計算力去生成相同的頁面,是不是很可怕?

          當然,使用緩存,在一定程序上增加了應用的復雜性。首先,每隔一段時間就需要使緩存失效并刷新,對吧?我們總不可能永遠返回相同的結果。另一個問題是,如果使用不合理,緩存容易膨脹,并導致內(nèi)存問題。

          好在,ASP.Net有很多已經(jīng)實現(xiàn)的優(yōu)秀的緩存庫可以幫助解決大部分的工作。

          4. 垃圾回收優(yōu)化

          應用服務器性能優(yōu)化中,垃圾回收是一個必須考慮的問題。

          我們知道,Dotnet垃圾回收有兩種不同的模式:工作站模式和服務器模式。前者被優(yōu)化為以最小的資源使用快速響應,而后者用于高吞吐量。

          Dotnet運行時默認將桌面應用程序中的GC模式設置為工作站模式,而服務器中的GC模式設置為服務器模式。這個默認值幾乎總是最好的。在服務器中,GC將使用更多的機器資源,但是能夠處理更大的吞吐量。換句話說,該進程將有更多的線程專門用于垃圾回收,它將能夠每秒釋放更多字節(jié)。

          相比由系統(tǒng)自動默認GC模式而言,手動設置應用的垃圾回收模式會是一個安全的做法。服務器并不是總能正確地意識到需要什么樣的回收模式。

          5. 減少不必要的客戶端請求

          客戶端請求的數(shù)量,很大程度上可以決定服務器的數(shù)量或服務器的負載。所以,通過一些技巧來減少服務器請求,也是優(yōu)化的一部分內(nèi)容。

          這個內(nèi)容需要在應用中具體探討或體會。我只舉幾個實用的例子:

          • 自動完成機制

          通常這種應用,就是我們在前端輸入時,客戶端從第一個輸入字符開始做API調(diào)用。比方我們輸入"Dotnet",那我們會向服務器發(fā)送6個請求 --- "D"、"Do"、"Dot"、"Dotn"等等。但實際上,考慮到輸入的連續(xù)性,我們可以在調(diào)用前,做個短時的延時,比方停止輸入500ms后才向服務器發(fā)送請求。你可能不會相信,我們實際應用中實測的結果,可以減少93%的調(diào)用。

          • 客戶端緩存

          還是上面的例子。對于同一個應用,很多位置的輸入都是相同或類似的。如果我們將自動完成的結果緩存在客戶端,而不是每次都發(fā)送這些請求,同樣可以減少很多不必要的請求。

          • 批處理

          應用中,一個頁面跟服務器的交互通常會有很多。通常最無腦的做法,就是一個事件發(fā)送一個請求。這樣的方式無形中會對服務器產(chǎn)生相當?shù)膲毫ΑH绻赡埽堰@樣的事件合并成一個請求,會更有效率,對服務器更友好。

          6. 正確處理掛起的請求

          客戶端對服務器的請求,可能會被掛起。也就是說,客戶端發(fā)送了一個請求,但未收到響應,或者準確地說,是經(jīng)過一個比較長的時間后,收到一個超時響應。雖然我們不希望發(fā)生這樣的事,但這種事情總在發(fā)生:處理請求時間過長、或代碼死鎖、或代碼出錯并且沒有正常捕獲錯誤,當然還包括等待一些本應該出現(xiàn)但實際未出現(xiàn)的東西,例如來自隊列的消息、長時間的數(shù)據(jù)庫響應或對另一個服務的調(diào)用。

          本質(zhì)上,當一個請求被掛起時,會掛起一個或多個線程。但應用程序并不會停,并繼續(xù)處理新的請求。如果這個掛起在其它請求上也有重現(xiàn),那隨著時間,掛起的線程將越來越多,并最終影響服務器或系統(tǒng)的響應。

          因此,請求掛起對服務器性能的影響非常大。

          這個問題的解決,需要針對核心的部分,就是掛起的部分進行調(diào)試,以確保程序處理了各種可能性,并不會產(chǎn)生任何意外的掛起。

          7. 服務器崩潰

          服務器崩潰也是一個可能的性能問題。

          通常來說,客戶端請求期間發(fā)生一般的異常時,應用程序不會崩潰。但總有一些問題,比方上下文之外的異常,或者一些災難性的異常,比方OutOfMemoryException、ExecutionEngineException、StackOverflowException,當這些發(fā)生時,不管加多少catch,也擋不住崩潰的發(fā)生。

          通常如果的托管在Web Server上,例如:IIS、Nginx、Jexus上的ASP.Net應用,崩潰時Web Server會自動回收資源,并重啟應用。客戶端的感覺是臨時的慢響應或503錯誤。

          而如果是直接啟動的ASP.Net應用,則程序會永久關閉,需要手動重啟。這將是一個問題。

          所以,一方面,使用Web Server會是一個好習慣。另一方面,還是要檢查代碼,從根本上解決問題。

          8. 永遠記著應用規(guī)模

          這個問題說起來很簡單,但實際開發(fā)中,其實經(jīng)常會忘記,或者說忽略應用的規(guī)模。

          • 用緩存,會忘了分布式緩存,忘了同步問題,直接使用單機內(nèi)存緩存;

          • 數(shù)據(jù)庫寫入,會忘了并發(fā)下的數(shù)據(jù)一致性問題;

          • 。。。太多了,不一一寫了

          解決的辦法,是從頭開始,就把代碼規(guī)模化 --- 從開發(fā)到測試,全部使用雙向擴展,即水平擴展(向外擴展)和垂直擴展(向上擴展)。垂直擴展意味著服務機器添加更多的功能,比如更多的CPU和RAM,而水平擴展意味著添加更多的機器。

          記著,從開發(fā)和測試開始,就要使用與生產(chǎn)環(huán)境使用同等規(guī)模的環(huán)境來做。

          9. 同步和異步

          應用服務不同于桌面應用或終端應用。當服務在執(zhí)行過程中需要等待響應時,比方數(shù)據(jù)庫操作、或者調(diào)用別的服務時,這個服務本身就開始有了一定的風險。如果數(shù)據(jù)庫或別的服務正忙著處理別的請求、或者存在性能問題時,必然會把性能問題傳遞到調(diào)用方。

          怎么辦?

          解決的基本模式是異步調(diào)用。異步調(diào)用有兩個含義:

          • 代碼的異步調(diào)用,就是我們常說的async和await。

          • 架構的異步調(diào)用。這個通常是通過使用Kafka或RabbitMQ這樣的隊列服務來完成。向隊列發(fā)送消息,并不等待響應。由另一個服務提取這些消息并處理。這個方式,通常是不需要回復的服務。而如果需要回復,也可以用類似SignalR這樣的推送通知。

          重要的是,這樣的方式下,系統(tǒng)組件不需要主動等待服務。一切都是異步處理的。服務之間的耦合可以松散很多。

          當然同樣的,這樣會讓代碼變得更復雜。

          取舍之間,是對代碼的控制力。

          10. 一個小總結

          出差期間,斷斷續(xù)續(xù)寫的這個東西,似乎有點亂,但就這樣吧

          在實際項目中,很多方面稍不注意,就能搞亂服務器的性能,而且有很多地方會出錯。而解決呢,又沒有捷徑和技巧,需要仔細的計劃,有經(jīng)驗的工程師,以及大量的緩沖時間來應對可能出現(xiàn)的問題。

          后面我寫寫一些工具的應用吧。很多方面,還是有好的工具可以幫助解決或至少是快速發(fā)現(xiàn)問題的。

          總之,這是一篇個人的經(jīng)驗之談,希望能給大家一個拋磚引玉的作用。

          回復 【關閉】
          回復 【實戰(zhàn)】獲取20套實戰(zhàn)源碼
          回復 【被刪】
          回復 【訪客】
          回復 【小程序】學獲取15套【入門+實戰(zhàn)+賺錢】小程序源碼
          回復 【python】學微獲取全套0基礎Python知識手冊
          回復 【2019】獲取2019 .NET 開發(fā)者峰會資料PPT
          回復 【加群】加入dotnet微信交流群

          去TM收費,我要在線 Vip 視頻解析!


          輸入任意文字即可激活,這款軟件愛了!


          瀏覽 50
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  色哟哟 入口国产精品 | 草无码 | 亚洲色图欧洲 | 免费伦片A片在线观看警官 | 最新国语对白精彩视频 |