Redis變慢?深入淺出Redis性能診斷系列文章(二)

来源:https://www.cnblogs.com/databasepub/archive/2022/09/13/16691141.html
-Advertisement-
Play Games

本篇為Redis性能問題診斷系列的第二篇,本文主要從應用發起的典型命令使用上進行講解,由於Redis為單線程服務架構,對於一些命令如果使用不當會極大的影響Redis的性能表現,這裡也會對不合理的使用方式給出優化解決方案。 ...


(本文首發於“資料庫架構師”公號,訂閱“資料庫架構師”公號,一起學習資料庫技術) 本篇為Redis性能問題診斷系列的第二篇,本文主要從應用發起的典型命令使用上進行講解,由於Redis為單線程服務架構,對於一些命令如果使用不當會極大的影響Redis的性能表現,這裡也會對不合理的使用方式給出優化解決方案。   一、Redis慢日誌功能 分析Redis訪問變慢,其中有個最基礎的方法就是先去看Redis是否有慢日誌【就像MySQL的慢SQL一樣】。Redis提供了一個簡單的慢命令統計記錄功能,它會記錄有哪些命令在執行時耗時較長。Redis慢日誌功能由兩個核心參數控制: slowlog-log-slower-than 1000 #慢日誌命令執行閾值,這裡指超過1ms就會被記錄【單位為微秒】 slowlog-max-len 4096 #保留慢日誌命令的個數,類似一個先進先出的隊列,超過4096個最早的就會被清理 Redis的這個慢日誌功能比較粗糙簡單,有個嚴重的不足:沒有持久化記錄能力。 由於Redis的慢日誌記錄都在記憶體中,不像MySQL會持久化到文件里,那麼如果慢日誌產生較快,即使設置的slowlog-max-len比較大也會很快被填滿,診斷問題時也就不能統計到那個時間段產生的所有慢命令詳情。 為了避免產生的慢日誌被清理,目前一個折中的解決方案是寫一個收集程式周期性的將新增慢命令查出並記錄到MySQL或者本地文件中,以備事後分析。但是這個頻率一般都是分鐘級,Redis處理的吞吐能力又太大,在慢命令較多的情況下往往也不能全部記錄下來。 配置好慢日誌相關閾值後,可以執行以下命令查詢最近的慢日誌記錄了: 127.0.0.1:6379> SLOWLOG get 5 1) 1) (integer) 42343    2) (integer) 1653659194 #慢日誌產生的時間戳    3) (integer) 73536      #慢日誌執行的耗時    4) 1) "KEYS"            #慢日誌命令詳情       2) "permission::userMenuList:*"    5) "192.168.1.11:20504"  #慢日誌命令發起來源IP【4.0及以後版本支持】    6) ""2) 1) (integer) 42342    2) (integer) 1653659194    3) (integer) 73650    4) 1) "KEYS"       2) "userPermission:*"    5) "192.168.1.10:20362"    6) "" 3) 1) (integer) 42341    2) (integer) 1653659193    3) (integer) 81505    4) 1) "KEYS"       2) "userRole:*"    5) "192.168.1.13:19926"    6) "" 二、幾種典型導致Redis變慢的不合理使用方式 1.使用keys命令進行正則匹配 Keys的正則匹配是阻塞式的、全量掃描過濾,這對於單線程服務的Redis來說是致命的,僅僅幾十萬個Key的匹配查詢在高併發訪問下就有可能將Redis打崩潰!這其實就像MySQL的無索引查詢大表數據,全表掃描狀態下幾個併發查詢就可能會將資料庫堵死。 redis> SLOWLOG get 5 1) 1) (integer) 42343    2) (integer) 1653659194    3) (integer) 73536    4) 1) "KEYS"       2) "Testper::userList:*"    5) "192.168.1.10:20504"    6) "" 2) 1) (integer) 42342    2) (integer) 1653659194    3) (integer) 73650    4) 1) "KEYS"       2) "TestuserPermission:*"    5) "192.168.1.11:20362"       6) "" 3) 1) (integer) 42341    2) (integer) 1653659193    3) (integer) 81505    4) 1) "KEYS"       2) "TestuserRole:*"    5) "192.168.1.12:19926"    6) "" 上述示例中使用Keys來模糊查詢某些Key,每次的執行都在70ms以上,嚴重影響了正常的Redis響應時長和吞吐。 針對這種問題的一個解決方案是使用scan代替keys。這是一個查詢迭代命令,用於迭代當前資料庫中的緩存數據。它是一個基於游標的迭代器,每次被調用之後, 都會向用戶返回一個新的游標, 用戶在下次迭代時需要使用這個新游標作為Scan命令的游標參數, 以此來延續之前的迭代過程。具體的命令語法這裡不再詳述。 2.大量使用了複雜度較高的命令 (1)應用中高頻使用了 O(N) 及以上複雜度的命令,例如:SUNION、SORT、ZUNIONSTORE、ZINTERSTORE 聚合類命令。SORT命令的時間複雜度:O(N+M*log(M)), N 為要排序的列表或集合內的元素數量, M 為要返回的元素數量。 這種導致Redis請求變慢的原因是,Redis 在操作數據排序時,時間複雜度過高,要花費更多的 CPU計算資源。 (2)使用 O(N) 複雜度的命令,但 N 的值非常大,比如hgetall、smembers、lrange、zrange等命令。 這種變慢的原因在於,Redis 一次需要返回給客戶端的數據過多,需要花費更多時間在數據組裝和網路傳輸中。對於hgetall、smembers這種命令,需要警惕項目剛上線之初hash、set或者list存儲的成員個數較少,但是隨著業務發展成員數量極有可能會膨脹的非常大,如果仍然採用上述命令不加控制,會極大拖累整個Redis服務的響應時間。 針對這兩種情況還都可以從資源使用率層面來分析,如果應用程式訪問 Redis 的QPS不是很大,但 Redis 實例的 CPU 使用率卻很高,那麼很有可能是使用了複雜度過高的命令導致的。 因為Redis 是單線程處理請求的,如果你經常使用以上複雜度較高的命令,那麼當 Redis 處理程式請求時,一旦前面某個命令發生耗時較長,就會導致後面的請求發生阻塞排隊,對於應用程式來說,響應延遲也會變長。 3.存儲使用了bigkey 在分析慢日誌發現很多請求並不是複雜度高的命令,都是一些del、set、hset等的低複雜度命令,那麼就要評估是否寫入了大key。 在往Redis寫入數據時,需要為新數據分配記憶體塊,相對應的,當刪除數據時,Redis也會釋放對應的記憶體空間。如果一個 key 寫入Redis的值非常大,那麼在分配記憶體時就會相對比較耗時。同樣的當刪除這個 key 時,釋放記憶體也會比較耗時,這種被稱為bigKey。 當然這個描述仍然比較寬泛,因為Redis中的資料庫結構類型比較多,更完善的一些說法可以這麼定義:將含有較大數據或含有大量成員、列表數的Key定義為bigkey。 我們一般要求研發使用Redis時,對於String類型Value大小不要超過1KB。 大Key帶來的問題比較多,主要有下麵幾種情況:
  • 由於大Key的記憶體分配及釋放開銷變大,直接影響就是導致應用訪問Redis的響應變慢;
  • 刪除時會造成較長時間的阻塞並有可能造成集群主備節點切換【4.0之前的版本有這個問題】;
  • 記憶體占用過多甚至達到maxmemory配置,會造成新寫入阻塞或一些不應該被提前刪除的Key被逐出,甚至導致OOM發生;
  • 併發讀請求因為Key過大會可能打滿伺服器帶寬,如果單機多實例部署則同時會影響到該伺服器上的其它服務【假設一個bigkey為1MB,客戶端每秒訪問量為1000,那麼每秒產生1000MB的流量】;
  • 運維麻煩,比如RedisCluster的數據跨節點均衡,因為均衡遷移原理是通過migrate命令來完成的,這個命令實際是通過dump + restore + del三個命令組合成原子命令完成,如果是bigkey,可能會使遷移失敗,而且較慢的migrate也會阻塞Redis正常請求;
  • 分片集群RedisCluster中的出現嚴重的數據傾斜,導致某個節點的記憶體使用過大;
那麼對於已經寫入的數據,如何分析找出裡面的bigkey進行優化呢?可以通過Redis官方客戶端redis-cli的bigkeys參數來定位大Key分佈。 shell> redis-cli -h 127.0.0.1 -p 18708 -a xxxx --bigkeys -i 0.01 [00.00%] Biggest string found so far 'urlcount:www.guprocessorSuccessMid' with 1 bytes [00.01%] Biggest string found so far 'TestDomain:www:config:scheduler' with 3847 bytes [00.03%] Biggest string found so far 'TestDomain:www:config:scheduler' with 211306 bytes [00.88%] Biggest set    found so far 'specialTestJobSet:www' with 20 members [01.69%] Biggest list   found so far 'TestDomain:www:urlList' with 9762 items [07.13%] Biggest list   found so far 'TestDomain:bx:urlList' with 457676 items [07.39%] Biggest set    found so far 'specialTestJobSet:www' with 100 members [13.99%] Biggest string found so far 'TestDomain:wwwe:config:scheduler' with 540731 bytes [18.74%] Biggest set    found so far 'TestJobSet' with 300 members [58.09%] Biggest string found so far 'TestDomain:wwwrt:config:scheduler' with 739024 bytes [64.19%] Biggest string found so far 'TestDomain:bx:config:scheduler' with 1335468 bytes   -------- summary ------- Sampled 62522 keys in the keyspace! Total key length in bytes is 2471471 (avg len 39.53) Biggest list found 'TestDomain:bx:urlList' has 457676 items Biggest string found 'TestDomain:bx:config:scheduler' has 1335468 bytes Biggest set found 'TestJobSet' has 300 members   208 lists with 2408539 items (00.33% of keys, avg size 11579.51) 0 hashs with 0 fields (00.00% of keys, avg size 0.00) 62283 strings with 32642667 bytes (99.62% of keys, avg size 524.10) 0 streams with 0 entries (00.00% of keys, avg size 0.00) 31 sets with 1354 members (00.05% of keys, avg size 43.68) 0 zsets with 0 members (00.00% of keys, avg size 0.00) 從輸出結果我們可以看到,每種數據類型所占用的最大長度或含有最多成員的 key 是哪一個,以及每種數據類型在整個實例中的占比和平均大小及成員數量。 其實,使用這個命令的原理就是 Redis 在內部執行了 SCAN 命令,遍歷整個實例中所有的 key,然後針對 key 的類型,分別執行 STRLEN、HLEN、LLEN、SCARD、ZCARD 命令,來獲取 String 類型的長度、集合類型(Hash、List、Set、ZSet)的成員個數. 註意,使用該--bigkeys進行大key的統計時要註意:
  • 對於集合類型的Hash、List、Set、ZSet僅僅統計的是包含的成員個數,個數多並代表占用的記憶體大,僅僅是個參考;
  • 對於高併發訪問的集群,使用該命令會造成QPS增加,帶來額外的性能開銷,建議在業務低峰或者從節點進行掃描。
那針對 bigkey 導致延遲的問題,有什麼好的解決方案呢? 1)對大Key進行拆分 如將一個含有數萬成員的HASH Key拆分為多個HASH Key,並確保每個Key的成員數量在合理範圍。特別是在RedisCluster架構下中,大Key的拆分對各節點間的記憶體平衡能夠起到顯著作用。 2)優化使用刪除Key的命令。 Redis自4.0起提供了UNLINK命令,該命令可以替換DEL,能夠以非阻塞的方式放到後臺線程中緩慢逐步的清理大Key所占用的記憶體塊,從而減輕了對Redis的影響; Redis 6.0 以上版本,建議開啟 lazy-free 機制(配置參數:lazyfree-lazy-user-del = yes,6.2版本之後預設開啟了),這樣在 DEL刪除大Key時,釋放記憶體的動作也是在後臺線程中執行的; 3)儘量不寫入大Key 首先評估使用其他的存儲形式,比如文檔性資料庫 MongoDB等;如果還無法避免使用BigKey,可以將大Key進行壓縮後存儲,並儘量根據業務精簡Value的內容;建議單個Key的大小不要超過1K; 4.不合理使用批處理命令 網上有不少關於批量處理的一些優化,使用mget、mset代替多次的get、set等,減少網路IO開銷以此提高redis的處理效率,特別是對於一些php短連接效果尤其明顯。 但是對於這些批量處理命令原生的mget、mset,非原生命令如pipeline,一定要註意控制單次批量操作的元素個數,否則會阻塞其它請求命令!建議控制在500以內。針對該種場景的優化方案:
  • 降低使用 O(N) 以上複雜度的命令,對於數據的計算聚合操作等可以適當的放在應用程式側處理;
  • 使用O(N) 複雜度的命令時,保證 N 儘量的小(推薦 N <= 500),每次處理的更小的數據量,降低阻塞的時長;
  • 對於Hgetall、Smembers操作的集合對象,應從應用層面保證單個集合的成員個數不要過大,可以進行適當的拆分等。
  5.大批量Key集中過期 經常遇見反饋我的應用沒有上線變更調整,但是訪問的Redis經常出現超時的問題。分析後現象大部分表現為:超時問題出現的時間點有規律,比如每隔一個小時出現一次,或者每天零點過後發生。 如果出現了這種情況,那麼需要從兩個方面排查一下:
  • 是否有定時任務的腳本程式,定時或者間隔性的操作Redis
  • Redis的Key數量出現集中過期清理
第一種情況這裡不做過多解讀,重點分析下Redis的Key數量為什麼會出現集中過期,集中過期為什麼會造成Redis的訪問變慢。 這就需要我們瞭解 Redis 的Key過期策略是怎樣的。Redis 的過期數據採用被動過期 + 主動過期兩種策略:
  • 被動過期:只有應用發起訪問某個key 時,才判斷這個key是否已過期,如果已過期,則從Redis中刪除
  • 主動過期:在Redis 內部維護了一個定時任務,預設每隔 100 毫秒(1秒10次)從全局的過期哈希表中隨機取出 20 個 key,判斷然後刪除其中過期的 key,如果過期 key 的比例超過了 25%,則繼續重覆此過程,直到過期 key 的比例下降到 25% 以下,或者這次任務的執行耗時超過了 25 毫秒,才會退出迴圈
註意:Redis的key主動過期清理的定時任務,是在 Redis 主線程中執行的,也就意味著會阻塞正常的請求命令。進一步說就是如果在執行主動過期的過程中,出現了需要大量刪除過期 key 的請求,那麼此時應用程式在訪問 Redis 時,必須要等待這個過期任務執行結束,Redis 才可以繼續處理新請求。此時現象就是上面說的應用訪問 Redis 延時突然變大了。 特別是由於批量清理Key這個操作的命令是內部發起的並不會記錄在慢日誌中,但我們的應用程式卻感知到了延遲變大,其實時間都花費在了刪除過期 key 上,這種情況就經常被忽略。 如果確實是集中過期 key 導致的訪問變慢,那麼可以採用如下處理方案: 業務Key設置過期時間時,預計的過期時間加上一個隨機過期時間段,比如5分鐘,將集中過期時間打散,降低 Redis批量清理時的壓力。 由於這種情況分析比較麻煩,強烈建議對過期key的數量進行監控,對於短時間過期較多key的情況進行預警,通過執行info命令獲取過期Key數量【expired_keys】的統計值: # Stats total_connections_received:1359356 total_commands_processed:2705619999 instantaneous_ops_per_sec:157 total_net_input_bytes:232498789314 total_net_output_bytes:279219680360 instantaneous_input_kbps:11.01 instantaneous_output_kbps:17.07 rejected_connections:0 sync_full:2 sync_partial_ok:1 sync_partial_err:0 expired_keys:215099347      evicted_keys:0 keyspace_hits:984222771 keyspace_misses:610235483 pubsub_channels:1 pubsub_patterns:0 latest_fork_usec:9484 說明:expired_keys為一個累計值,可以在監控系統中配置為1分鐘的增加值,當1分鐘過期的key超過一定閾值時進行預警。 6.預估記憶體不足,使用的數據記憶體達到了最大值 由於伺服器記憶體有限,一般使用Redis時都會配置當前實例可用的最大記憶體maxmemory,那麼當使用的記憶體達到了 maxmemory 後,雖然配置了數據的自動淘汰策略,但是在此之後每次寫入新數據,操作延遲都會變長。 核心原因在於,當 Redis 記憶體達到 maxmemory 後,每次寫入新的數據之前,Redis 必須先從實例中剔除一部分數據,讓整個實例的記憶體維持在 maxmemory 之下,然後才能把新數據寫進來。 這裡很多同學會有誤解,以為只要配置了maxmemory就可以了,實際上由於Redis特殊的清理策略,無法避免會對正常的使用造成影響! 為了降低記憶體自動清理對服務的影響,可以配置Redis的最大記憶體數據清理策略,主要有以下幾種:
  • allkeys-lru:清理最近最少使用(LRU)的Key,不管 key 是否設置了過期時間
  • volatile-lru:清理最近最少使用(LRU)的Key,但是只回收有設置過期的Key
  • allkeys-random:隨機清理部分Key,不管 key 是否設置了過期時間
  • allkeys-lfu:不管 key 是否設置了過期,清理訪問頻次最低的 key(4.0+版本支持)
  • volatile-lfu:清理訪問頻次最低且設置了過期時間 key(4.0+版本支持)
  • volatile-random:隨機清理部分設置了過期時間的部分Key
  • volatile-ttl:清理有設置過期的Key,嘗試先回收離 TTL 最短時間的Key
  • noeviction:不清理任何Key,當到達記憶體最大限制時,當客戶端嘗試執行命令時會導致更多記憶體占用時直接返回錯誤(大多數寫命令,除了 DEL 和一些例外)。
使用哪種清理策略,我們需要根據實際的應用場景來選擇,比如有些業務用於存儲強調準確性,即使訪問有損了也不能逐出數據,那麼就要配置noeviction;還有些業務是緩存,有些清理那些早期寫入的Key,則可以選擇volatile-lru或allkeys-lru。 介紹下常使用的是 allkeys-lru / volatile-lru 的淘汰策略,它們的處理邏輯是,每次從實例中隨機取出一批 key(maxmemory-samples控制數量),然後淘汰一個最少訪問的key,然後把剩餘的 key 暫存到一個池子中,繼續隨機取一批 key,並與之前池子中的 key 比較,再淘汰一個最少訪問的 key。以此迴圈往複,直到實例記憶體降到 maxmemory值以下才停止。所以這段時間是會影響新的數據寫入的,應用層就會有超時或者請求響應變慢的問題發生。 針對記憶體達到上限的情況,可以採用如下優化方案:
  • 合理預估記憶體占用,避免達到記憶體的使用上限。這裡有兩種方法可以參考:
(1)根據寫入Key的類型、數量及平均大小計算預估,不同的數據類型有不同的數據結構及編碼方式,後續開文專門介紹; (2)寫入一小部分比例的真實業務數據,然後進行預估。
  • 設置合理的Key過期時間,滿足業務的最小保留時間即可。
  • 數據量過大建議拆分成多套Redis或者使用RedisCluster分片集群,建議單集群最大記憶體不超過20G。
  • 數據清理策略改為隨機模式,隨機清理比 LRU 要快很多(不過這個要根據業務情況評定,業務優先滿足原則)。
  • 如果使用的是 Redis 4.0 及以上版本,開啟 layz-free 機制,把淘汰 key 釋放記憶體的操作放到後臺線程中執行(配置 lazyfree-lazy-eviction = yes)
  • 增加剩餘可用記憶體的監控,提前預警併進行最大記憶體上限的擴容或者提前清理釋放記憶體。
7.實際請求量超過了Redis的處理能力 Redis處理速度再快,也有達到上限的時候。特別是一些大促活動時,業務流量往往出現暴漲,很容易就會達到Redis的處理瓶頸。這種在業務上的表現除了訪問Redis變慢,一些簡單的命令如get、set也開始出現在慢日誌中。 這時如果查看Redis的CPU使用情況,基本是100%的狀態,那麼大概率就是達到Redis的處理能力上限了。   為瞭解決這種問題,就需要評估當前集群的處理吞吐力,參考官方的測評結果QPS 10W行不行?我們在上一篇文章介紹基本的壓測有過說明,每個Redis所在的伺服器配置不一樣,處理能力就不一樣。 更進一步說,每個Redis承載的服務模型不同,比如使用的命令類型、訪問比例等,那麼處理的吞吐也會有很大不同。針對這種情況最好的方案就是業務上線前,可以模擬真實的業務進行壓力測評,給出一個大概的吞吐處理能力。如果評估單節點無法承載過多請求,建議進行讀寫分離架構或者拆分為多套集群擴容. 最後就是不要忽略運維監控,可以對使用的CPU使用率、訪問的QPS等進行有效監控,提前發現是否達到集群的處理瓶頸,並決定是否進行擴容或架構調整。 說明:Redis監控指標還是比較多的,不管是性能指標、記憶體使用、持久化、網路連接等,後面會專門發文介紹,大家到時也可以關註下。   如果這篇文章對你有幫助,還請幫忙點贊、在看、轉發 一下,你的支持會激勵我們輸出更多高質量的文章,非常感謝! 如果你還想看更多優質文章,歡迎關註我的公號「資料庫架構師」,提升資料庫技能。    
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 上一篇《ORM增刪改查併發性能測試》出現了點小失誤,有的輸出SQL日誌的代碼沒有禁用,資料庫連接字元串可能有問題。統一環境,統一代碼後,重新寫一篇。 這次重點是併發性能測試,真不是為了diss其它ORM,開始是因為我寫的Dapper.LiteSql高併發場景下存在BUG,才寫了這個測試,經過修 ...
  • 痞子衡嵌入式半月刊: 第 61 期 這裡分享嵌入式領域有用有趣的項目/工具以及一些熱點新聞,農曆年分二十四節氣,希望在每個交節之日準時發佈一期。 本期刊是開源項目(GitHub: JayHeng/pzh-mcu-bi-weekly),歡迎提交 issue,投稿或推薦你知道的嵌入式那些事兒。 上期回顧 ...
  • 一.歐亞經濟委員會確認EAEU EAC的Safety以及EMC證書的有效期 歐亞經濟委員會(EEC)近期通過第 113 號、114號決議,確認在2022年12月11日之前,未按第90、91號決議取得的EAEU EAC TR CU 004/2011(低電壓設備的Safety)以及TR CU 020/2 ...
  • TCP編程模型 server創建socket套接字 socket套接字--可以理解為文件描述符(file descriptor),UNIX把網路看成文件 /** * @param domain domain參數指定了一個通信域;它選擇了將被用於通信的協議族。 比如 AF_UNIX AF_INET * ...
  • 1.vim三種模式 | 模式 |操作 | | : : | : : | | 可視模式 | 可查看內容 | | 編輯模式 | 可查看可修改內容 | | 命令行模式 | 給vim發送控制命令,可查看內容 | 註:打開文件,預設是可視模式 2.三種模式的切換 可視模式下 按i/a/o鍵 >進入編輯模式 編輯 ...
  • 如果您還為數學計算的繁瑣,函數作圖的費事,所畫圖形的不規範二煩惱的話,那麼您真的需要這款Mathematica 13 for Mac(科學計算軟體),是Mac平臺上致力於科學計算的軟體,很好地結合了數值和符號計算引擎、圖形系統、編程語言、文本系統、和與其他應用程式的高級連接。很多功能在相應領域內處於 ...
  • ####1. whoami--查看當前登錄的用戶名 book@100ask:~/linux$ whoami book ####2. echo--列印命令,配合'>'或者'>>'使用 echo 列印信息 //輸出信息到終端 echo 列印信息 > 文件名 //先清空文件裡面的內容,然後將輸出信息保存到 ...
  • 作者:小牛呼嚕嚕 | https://xiaoniuhululu.com 電腦內功、JAVA底層、面試相關資料等更多精彩文章在公眾號「小牛呼嚕嚕 」 現代電腦系統 現代電腦系統與馮·諾依曼電腦差別不大,最大的區別馮·諾依曼電腦 是 以運算器為中心的,而現代電腦 以儲存器為中心: 我們主要 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...