介面性能優化方案及其理論依據

来源:http://www.cnblogs.com/xiexj/archive/2017/08/02/7275752.html
-Advertisement-
Play Games

我們現在介面的線上問題主要有三個,第一:啟動時有些機器會有短暫的線程池滿。第二:併發量上不去,怕服務被打死,不敢調高限流閾值。第三:499超時現象。 今天已上線 今天終於把那天說的全量執行時間延長,從圖中可以看到,中午12點發版之後,記憶體使用率有明顯下降,晚上是介面調用高峰,會有上浮,但是總體來看還 ...


  我們現在介面的線上問題主要有三個,第一:啟動時有些機器會有短暫的線程池滿。第二:併發量上不去,怕服務被打死,不敢調高限流閾值。第三:499超時現象。

今天已上線

  今天終於把那天說的全量執行時間延長,從圖中可以看到,中午12點發版之後,記憶體使用率有明顯下降,晚上是介面調用高峰,會有上浮,但是總體來看還是下降了。

 

 再來看看上線後的gc情況。目前是高峰期,gc控制在十幾秒一次,minor gc得到了控制。

  但是這個調優對線上問題一個也不能說是解決,具體真正的作用要靠觀察。期望的效果是高峰時cpu峰值不會猛增。這樣就可以考慮提高限流閾值了。第一個問題,啟動時有些機器會有短暫的線程池滿。今天發版倒是沒有發生,原因是我將dubbo的介面暴露時間延長到66秒。但是8台provider都沒有發生線程池滿,說明我分析出問題的原因是對的。

接下來的方案

  1>將servlet載入本地緩存改為spring task方式(個人時間和精力問題,如果部門內部可以找到人和我一起做就做,否則視情況而定)

  上次開會我說單開一個servlet來載入本地緩存開銷很大,不合理,應該改為spring task方式。德偉男神說別的部門也有這麼做的。阿裡的陽哥也說servlet沒問題。好吧,牛人都這麼說,我自己思維邏輯沒組織好之前就不和你們爭辯了。今天我梳理好了,來具體說一說。

  單看servlet的源碼,除了初始化過程,其他的過程似乎是有請求過來才調用, 沒有請求就不調用,開銷不是很大。但是請不要忽略了servlet放到resin這個servlet容器之後的生命周期。servlet容器是基於觀察者模式設計的,所有的容器都會繼承Lifecycle介面,它管理著容器的整個生命周期,所有容器的修改和狀態的改變都會由它去通知已經註冊的觀察者(Listener)。所以這個開銷在這裡,我只是想執行一個定時任務,容器卻給了一個專門的監聽線程來監聽。

  當時用這個來做,我猜測開發者的意圖是想一開始就先載入這個,儘量預載入。我測試過,spring task是spring初始化一完成就開始執行。我單用new Thread().start和spring task同時初始化一個map。誰先執行到是隨機的。所以,大可不必擔心。

  但是如果今天的調整,cpu使用得到控制,瓶頸不在這裡的話,這個不是當務之急。

       2>將增量和全量從資料庫定時拉取更新本地緩存的方式改為單獨後臺任務更新redis緩存,provider服務初始從redis取數據,只一個阻塞線程監聽redis訂閱事件來增量更新本地緩存(個人時間和精力問題,如果部門內部可以找到人和我一起做就做,否則視情況而定)

  這個我已經在離線項目中進行了性能測試。至少可以將初始載入速度提高10倍,但不穩定,主要取決於網路和網跳network hoops。

  根據數據的量級,主要細分為兩種方案:

  • 針對總數為500條以下的小數據,本地緩存可以直接採用redis的哈希結構。單有一個key保存最後更新時間(資料庫的unix timestamp,採用伺服器時間,各個伺服器之間時間不同步就不准了)。後臺定時更新redis哈希內的數據。有數據變更時,更新最後更新時間,發一個發佈消息帶有更新的id,通知更新。provider服務初始啟動時獲取redis中最後更新時間和哈希數據,直接反序列化整個redis哈希結構,減少了資料庫操作(這個也是需要字元串反序列化成對象的,持久層容器實現)和將list轉成map的時間和cpu操作。看到服務重啟cpu瞬間峰值,長成下麵的樣子。provider運行時收到更新,從redis中獲取此最新的ID值更新本地緩存。

  • 針對500條以上的大數據,區別在於此時redis哈希結構效率極低,直接用我自己存成帶壓縮的二進位方式(此帶壓縮的二進位序列化和反序列化方法我上傳到了epiphany項目中,歡迎大家體驗我的開源項目:http://github.com/xiexiaojing/epiphany)進行序列化和反序列化整個全量。provider運行時收到更新,然後可以去資料庫取本地的最後更新時間到當前時間的增量,更新本地緩存。下麵是一個2w多個鍵的本地緩存數據,可以看到其資料庫操作時間就已經遠遠超過從redis中取數據的時間。

  但是如果今天的調整,cpu使用得到控制,瓶頸不在這裡的話,這個不是當務之急。

  3>dubbo 業務線程數減小

   我看到provider服務的dubbo業務線程數設置了800,而dubbo預設是200,一般的項目也就是100。我很理解,感性上去想業務線程數越大不是處理能力越強嗎?其實還真不是。前段時間我在想,為什麼我們一般的499超時都是單台單台的報,不是幾台一起報,按理說平均每台1k多的QPS,採用的是random負載均衡策略不應該是這個效果。問題就在這裡了。如果我們設置了業務線程數是200,因為我們的iothread數是0,那麼來了800個請求其他600個請求就會分到其他伺服器上去。而我們設置800個線程,壓力都集中在這一個上面,負載均衡策略沒有很好的發揮作用。還有就是線程數多了,處理能力下降,響應時間會變慢。處理能力為啥會下降呢?線程的上下文切換啊。而且各種資源消耗都很大。如果降低這個業務線程數,還可以增加棧記憶體和TLAB,提高處理速度。棧記憶體為啥能提高處理速度?棧內分配,逃逸分析,內聯優化等等。TLAB是線程本地分配緩存,是新生代的一小塊區域,大小可調。是線程專享的。不加鎖,速度快。這個做了,對499會有顯著效果。

還需要考慮的

   介面還存在一些memcached超時。這就是為什麼我搭建了一套redis集群。需要對緩存用資料庫和redis做壓力分散。我在弄一個叫cloudrise的開源項目是spring data redis的升級版,要實現的主要目標是減少network hoops和集成一些高效的序列化和反序列化方法,如protobuf。另外還考慮在redis前加一個類似於memcached的moxi代理的本地緩存和管道key合併提高效率。項目地址是:https://github.com/xiexiaojing/cloudrise。現在還沒有完全實現,但是各種command介面有很詳細的中文註釋,我覺得用這個代碼來學習redis比我現在看過的redis的書要好很多。介紹的很詳細。行到水窮處,坐看雲起時,歡迎使用cloudrise~~

package com.brmayi.cloudrise.connection.commands;

import java.util.List;
import java.util.Properties;

import com.brmayi.cloudrise.connection.RedisClusterNode;
import com.brmayi.cloudrise.core.types.RedisClientInfo;
/**
 * <pre>
 * *********************************************************************************************************
 * 版權所有(C) 2017 cloudrise 
 * 保留所有權利。
 *            .==.       .==.
 *           //'^\\     //^'\\
 *          // ^^\(\__/)/^ ^^\\
 *         //^ ^^ ^/6  6\ ^^^ \\
 *        //^ ^^ ^/( .. )\^ ^^ \\
 *       // ^^  ^/\|v""v|/\^^ ^ \\
 *      // ^^/\/  / '~~' \ \/\^ ^\\
 *      ----------------------------------------
 *      HERE BE DRAGONS WHICH CAN CREATE MIRACLE
 * *********************************************************************************************************
 * 基本信息
 * *********************************************************************************************************
 * 系統:cloudrise
 * 支持:jdk1.7及以上 redis2.6.0及以上
 * 模塊:cloudrise commands
 * 功能:提供對Redis的伺服器操作抽象(所有的key和value都不能為null),每一個方式對應於一個redis命令。需指定節點
 * 編碼:靜兒([email protected])
 * 時間: 2017.08.01
 * *********************************************************************************************************
 * 修改歷史
 * *********************************************************************************************************
 * 修改者                            									           修改內容                      修改時間 
 * 靜兒([email protected])                            新建                             2017.08.01
 * *********************************************************************************************************
 * </pre>
 */
public interface RedisClusterServerCommands extends RedisServerCommands {


	/**
	 * 執行一個 AOF文件 重寫操作。重寫會創建一個當前 AOF 文件的體積優化版本。
	 * 即使 BGREWRITEAOF 執行失敗,也不會有任何數據丟失,因為舊的 AOF 文件在 BGREWRITEAOF 成功之前不會被修改。
	 * 重寫操作只會在沒有其他持久化工作在後臺執行時被觸發,也就是說:
	 * 如果 Redis 的子進程正在執行快照的保存工作,那麼 AOF 重寫的操作會被預定(scheduled),等到保存工作完成之後再執行 AOF 重寫。
	 * 在這種情況下, BGREWRITEAOF 的返回值仍然是 OK ,但還會加上一條額外的信息,說明 BGREWRITEAOF 要等到保存操作完成之後才能執行。
	 * 在 Redis 2.6 或以上的版本,可以使用 INFO 命令查看 BGREWRITEAOF 是否被預定。
	 * 如果已經有別的 AOF 文件重寫在執行,那麼 BGREWRITEAOF 返回一個錯誤,並且這個新的 BGREWRITEAOF 請求也不會被預定到下次執行。
	 * 從 Redis 2.4 開始, AOF 重寫由 Redis 自行觸發, BGREWRITEAOF 僅僅用於手動觸發重寫操作。
	 * 時間複雜度:O(N), N 為要追加到 AOF 文件中的數據數量。
	 * @param node 節點
	 * @since 1.3
	 * @see <a href="http://redis.io/commands/bgrewriteaof">Redis Documentation: BGREWRITEAOF</a>
	 */
	void bgReWriteAof(RedisClusterNode node);

	/**
	 * 在後臺非同步(Asynchronously)保存當前資料庫的數據到磁碟。
	 * BGSAVE 命令執行之後立即返回 OK ,然後 Redis fork 出一個新子進程,原來的 Redis 進程(父進程)繼續處理客戶端請求,而子進程則負責將數據保存到磁碟,然後退出。
	 * 客戶端可以通過 LASTSAVE 命令查看相關信息,判斷 BGSAVE 命令是否執行成功。
	 * @param node 節點
	 * @see <a href="http://redis.io/commands/bgsave">Redis Documentation: BGSAVE</a>
	 */
	void bgSave(RedisClusterNode node);


	/**
	 * 返回最近一次 Redis 成功將數據保存到磁碟上的時間,以 UNIX 時間戳格式表示。
	 * 時間複雜度:O(1)
	 * @param node 節點
	 * @return 一個 UNIX 時間戳。
	 * @see <a href="http://redis.io/commands/lastsave">Redis Documentation: LASTSAVE</a>
	 */
	Long lastSave(RedisClusterNode node);


	/**
	 * SAVE 命令執行一個同步保存操作,將當前 Redis 實例的所有數據快照(snapshot)以 RDB 文件的形式保存到硬碟。
	 * 一般來說,在生產環境很少執行 SAVE 操作,因為它會阻塞所有客戶端,保存資料庫的任務通常由 BGSAVE 命令非同步地執行。
	 * 然而,如果負責保存數據的後臺子進程不幸出現問題時, SAVE 可以作為保存數據的最後手段來使用。
	 * 時間複雜度:O(N), N 為要保存到資料庫中的 key 的數量。
	 * @param node 節點
	 * @see <a href="http://redis.io/commands/save">Redis Documentation: SAVE</a>
	 */
	void save(RedisClusterNode node);


	/**
	 * 返回當前資料庫的 key 的數量。
	 * 時間複雜度:O(1)
	 * @param node 節點
	 * @return 返回當前資料庫的 key 的數量。
	 * @see <a href="http://redis.io/commands/dbsize">Redis Documentation: DBSIZE</a>
	 */
	Long dbSize(RedisClusterNode node);


	/**
	 * 清空當前資料庫中的所有 key。此命令從不失敗。
	 * 時間複雜度:O(1)
	 * @param node 節點
	 * @see <a href="http://redis.io/commands/flushdb">Redis Documentation: FLUSHDB</a>
	 */
	void flushDb(RedisClusterNode node);


	/**
	 * 清空整個 Redis 伺服器的數據(刪除所有資料庫的所有 key )。此命令從不失敗。
	 * @param node 節點
	 * @see <a href="http://redis.io/commands/flushall">Redis Documentation: FLUSHALL</a>
	 */
	void flushAll(RedisClusterNode node);


	/**
	 * Redis Info 命令以一種易於理解和閱讀的格式,返回關於 Redis 伺服器的各種信息和統計數值。
	 * 命令返回信息示例:
	 * <pre>
	 * # Server
	 * redis_version:3.2.9
	 * redis_git_sha1:00000000
	 * redis_git_dirty:0
	 * redis_build_id:a6f5b91b81bb8d8c
	 * redis_mode:cluster
	 * os:Linux 2.6.32-926.504.30.3.letv.el6.x86_64 x86_64
	 * arch_bits:64
	 * multiplexing_api:epoll
	 * gcc_version:4.4.7
	 * process_id:17612
	 * run_id:5644a791339db3e67cfb4ad4c529fee624e83326
	 * tcp_port:6379
	 * uptime_in_seconds:1299970
	 * uptime_in_days:15
	 * hz:10
	 * lru_clock:8405316
	 * executable:/letv/apps_install/redis-3.2.9/redis0/./redis-server
	 * config_file:/letv/apps_install/redis-3.2.9/redis0/redis.conf
	 * # Clients
	 * connected_clients:5
	 * client_longest_output_list:0
	 * client_biggest_input_buf:0
	 * blocked_clients:0
	 * 
	 * # Memory
	 * used_memory:1452392
	 * used_memory_human:1.39M
	 * used_memory_rss:3137536
	 * used_memory_rss_human:2.99M
	 * used_memory_peak:1491800
	 * used_memory_peak_human:1.42M
	 * total_system_memory:135210921984
	 * total_system_memory_human:125.92G
	 * used_memory_lua:37888
	 * used_memory_lua_human:37.00K
	 * maxmemory:0
	 * maxmemory_human:0B
	 * maxmemory_policy:noeviction
	 * mem_fragmentation_ratio:2.16
	 * mem_allocator:jemalloc-4.0.3
	 * 
	 * # Persistence
	 * loading:0
	 * rdb_changes_since_last_save:0
	 * rdb_bgsave_in_progress:0
	 * rdb_last_save_time:1500277631
	 * rdb_last_bgsave_status:ok
	 * rdb_last_bgsave_time_sec:0
	 * rdb_current_bgsave_time_sec:-1
	 * aof_enabled:1
	 * aof_rewrite_in_progress:0
	 * aof_rewrite_scheduled:0
	 * aof_last_rewrite_time_sec:0
	 * aof_current_rewrite_time_sec:-1
	 * aof_last_bgrewrite_status:ok
	 * aof_last_write_status:ok
	 * aof_current_size:25302
	 * aof_base_size:25302
	 * aof_pending_rewrite:0
	 * aof_buffer_length:0
	 * aof_rewrite_buffer_length:0
	 * aof_pending_bio_fsync:0
	 * aof_delayed_fsync:0
	 * 
	 * # Stats
	 * total_connections_received:15305
	 * total_commands_processed:86898
	 * instantaneous_ops_per_sec:0
	 * total_net_input_bytes:2016530
	 * total_net_output_bytes:859156
	 * instantaneous_input_kbps:0.00
	 * instantaneous_output_kbps:0.00
	 * rejected_connections:0
	 * sync_full:0
	 * sync_partial_ok:0
	 * sync_partial_err:0
	 * expired_keys:0
	 * evicted_keys:0
	 * keyspace_hits:0
	 * keyspace_misses:0
	 * pubsub_channels:0
	 * pubsub_patterns:0
	 * latest_fork_usec:292
	 * migrate_cached_sockets:0
	 * 
	 * # Replication
	 * role:slave
	 * master_host:10.127.95.184
	 * master_port:6381
	 * master_link_status:down
	 * master_last_io_seconds_ago:-1
	 * master_sync_in_progress:0
	 * slave_repl_offset:1
	 * master_link_down_since_seconds:1298428
	 * slave_priority:100
	 * slave_read_only:1
	 * connected_slaves:0
	 * master_repl_offset:0
	 * repl_backlog_active:0
	 * repl_backlog_size:1048576
	 * repl_backlog_first_byte_offset:0
	 * repl_backlog_histlen:0
	 * 
	 * # CPU
	 * used_cpu_sys:1273.56
	 * used_cpu_user:715.02
	 * used_cpu_sys_children:0.00
	 * used_cpu_user_children:0.00
	 * 
	 * # Cluster
	 * cluster_enabled:1
	 * 
	 * # Keyspace
	 * db0:keys=6,expires=0,avg_ttl=0
	 * </pre>
	 * @param node 節點
	 * @return 信息如上
	 * @see <a href="http://redis.io/commands/info">Redis Documentation: INFO</a>
	 */
	Properties info(RedisClusterNode node);


	/**
	 * Load server information for given {@code selection}.
	 * 命令示例如下:
	 * <pre>
	 * 10.183.96.194:6379> info memory
	 * </pre>
	 * 命令返回結果如下:
	 * # Memory
	 * used_memory:1452392
	 * used_memory_human:1.39M
	 * used_memory_rss:3137536
	 * used_memory_rss_human:2.99M
	 * used_memory_peak:1491800
	 * used_memory_peak_human:1.42M
	 * total_system_memory:135210921984
	 * total_system_memory_human:125.92G
	 * used_memory_lua:37888
	 * used_memory_lua_human:37.00K
	 * maxmemory:0
	 * maxmemory_human:0B
	 * maxmemory_policy:noeviction
	 * mem_fragmentation_ratio:2.16
	 * mem_allocator:jemalloc-4.0.3
	 * @param node 節點
	 * @return 信息如上
	 * @see <a href="http://redis.io/commands/info">Redis Documentation: INFO</a>
	 */
	Properties info(RedisClusterNode node, String section);


	/**
	 * SHUTDOWN 命令執行以下操作:
	 * 停止所有客戶端
	 * 如果有至少一個保存點在等待,執行 SAVE 命令
	 * 如果 AOF 選項被打開,更新 AOF 文件
	 * 關閉 redis 伺服器(server)
	 * 如果持久化被打開的話, SHUTDOWN 命令會保證伺服器正常關閉而不丟失任何數據。
	 * 
	 * 另一方面,假如只是單純地執行 SAVE 命令,然後再執行 QUIT 命令,則沒有這一保證 —— 因為在執行 SAVE 之後、執行 QUIT 之前的這段時間中間,其他客戶端可能正在和伺服器進行通訊,這時如果執行 QUIT 就會造成數據丟失。
	 * 
	 * SAVE 和 NOSAVE 修飾符
	 * 通過使用可選的修飾符,可以修改 SHUTDOWN 命令的表現。比如說:
	 * 執行 SHUTDOWN SAVE 會強制讓資料庫執行保存操作,即使沒有設定(configure)保存點
	 * 執行 SHUTDOWN NOSAVE 會阻止資料庫執行保存操作,即使已經設定有一個或多個保存點(你可以將這一用法看作是強制停止伺服器的一個假想的 ABORT 命令)
	 * @param node 節點
	 * @see <a href="http://redis.io/commands/shutdown">Redis Documentation: SHUTDOWN</a>
	 */
	void shutdown(RedisClusterNode node);


	/**
	 * CONFIG GET 命令用於取得運行中的 Redis 伺服器的配置參數(configuration parameters),
	 * 在 Redis 2.4 版本中, 有部分參數沒有辦法用 CONFIG GET 訪問,但是在最新的 Redis 2.6 版本中,所有配置參數都已經可以用 CONFIG GET 訪問了。
	 * CONFIG GET 接受單個參數 parameter 作為搜索關鍵字,查找所有匹配的配置參數,其中參數和值以“鍵-值對”(key-value pairs)的方式排列。
	 * 比如執行 CONFIG GET s* 命令,伺服器就會返回所有以 s 開頭的配置參數及參數的值:
	 *
	 * @param pattern 不能為空
	 * @return 結果示例如下:
	 * <pre>
	 *  1) "slave-announce-ip"
	 *  2) ""
	 *  3) "set-max-intset-entries"
	 *  4) "512"
	 *  5) "slowlog-log-slower-than"
	 *  6) "10000"
	 *  7) "slowlog-max-len"
	 *  8) "128"
	 *  9) "slave-priority"
	 * 10) "100"
	 * 11) "slave-announce-port"
	 * 12) "0"
	 * 13) "slave-serve-stale-data"
	 * 14) "yes"
	 * 15) "slave-read-only"
	 * 16) "yes"
	 * 17) "stop-writes-on-bgsave-error"
	 * 18) "yes"
	 * 19) "supervised"
	 * 20) "no"
	 * 21) "syslog-facility"
	 * 22) "local0"
	 * 23) "save"
	 * 24) "900 1 300 10 60 10000"
	 * 25) "slaveof"
	 * 26) "10.127.95.184 6381"
	 * </pre>
	 * @param node 節點
	 * @see <a href="http://redis.io/commands/config-get">Redis Documentation: CONFIG GET</a>
	 */
	Properties getConfig(RedisClusterNode node, String pattern);


	/**
	 * CONFIG SET 命令可以動態地調整 Redis 伺服器的配置(configuration)而無須重啟。
	 * 你可以使用它修改配置參數,或者改變 Redis 的持久化(Persistence)方式。
	 * CONFIG SET 可以修改的配置參數可以使用命令 CONFIG GET * 來列出,所有被 CONFIG SET 修改的配置參數都會立即生效。
	 * @param node 節點
	 * @param param 參數
	 * @param value 要設定的值
	 * @see <a href="http://redis.io/commands/config-set">Redis Documentation: CONFIG SET</a>
	 */
	void setConfig(RedisClusterNode node, String param, String value);


	/**
	 * 重置 INFO 命令中的某些統計數據,包括:
	 * Keyspace hits (鍵空間命中次數)
	 * Keyspace misses (鍵空間不命中次數)
	 * Number of commands processed (執行命令的次數)
	 * Number of connections received (連接伺服器的次數)
	 * Number of expired keys (過期key的數量)
	 * Number of rejected connections (被拒絕的連接數量)
	 * Latest fork(2) time(最後執行 fork(2) 的時間)
	 * The aof_delayed_fsync counter(aof_delayed_fsync 計數器的值)
	 * @param node 節點
	 * @see <a href="http://redis.io/commands/config-resetstat">Redis Documentation: CONFIG RESETSTAT</a>
	 */
	void resetConfigStats(RedisClusterNode node);


	/**
	 * 返回當前伺服器時間。
	 * @param node 節點
	 * @return TIME命令是一個包含兩個字元串的列表: 第一個字元串是當前時間(以 UNIX 時間戳格式表示),而第二個字元串是當前這一秒鐘已經逝去的微秒數。返回值是前一個
	 * @since 1.1
	 * @see <a href="http://redis.io/commands/time">Redis Documentation: TIME</a>
	 */
	Long time(RedisClusterNode node);

	/**
	 * 以人類可讀的格式,返回所有連接到伺服器的客戶端信息和統計數據。
	 * @param node 節點
	 * @return 所有連接到伺服器的客戶端信息和統計數據。
	 * @since 1.3
	 * @see <a href="http://redis.io/commands/client-list">Redis Documentation: CLIENT LIST</a>
	 */
	List<RedisClientInfo> getClientList(RedisClusterNode node);
}

  


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

-Advertisement-
Play Games
更多相關文章
  • 1. echo count(“abcd”);輸出多少? 答案:4 2. 運行以下代碼後$a $b $c 分別是? 答案:false、0、0 4. 請用php的heredoc語法格式輸出:hello world! 5. $string = "abcdefg",那麼$string{4}的值是? 答案:e ...
  • 恢復內容開始 1.下麵程式輸出是什麼? 結果: 5 2. 寫一個函數Check_ip,使用正則表達式檢測一個IPV4的IP是否正確,正確返回1,錯誤返回0,例如 Check_ip(‘127.0.0.1’)。 3. 請指出以下代碼的錯誤之處(圈出來並加以改正): 4. 有一數組 $a=array(4, ...
  • 使用cbind()函數連接多個向量來創建數據幀。此外,使用rbind()函數合併兩個數據幀 使用merge()函數合併兩個數據幀。數據幀必須具有相同的列名稱,在其上進行合併 melt()拆分數據和cast()數據重構 連接字元串 - paste()函數 格式化數字和字元串 - format()函數 ...
  • 在前面的幾個章節中,我們的程式都是只有一個代碼段,本章我們開始學習如何編寫包含多個段的程式。 1、在代碼段中使用數據 首先考慮這樣一個問題,計算以下8個數據的和,結果存放在ax寄存器中: 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H 在前面的課程中, ...
  • Python for迴圈可以遍歷任何序列的項目,如一個列表或者一個字元串。 語法: for迴圈的語法格式如下: good 記憶體為字典,提前預習了一下字典的寫法,這裡字典跟REDIS 的鍵值很像。 ...
  • Description: 我們現在要利用 m 台機器加工 n 個工件,每個工件都有 m 道工序,每道工序都在不同的指定的機器上完成。每個工件的每道工序都有指定的加工時間。 每個工件的每個工序稱為一個操作,我們用記號 j-k 表示一個操作,其中 j 為 1 到 n 中的某個數字,為工件號; k 為 1 ...
  • Java的MVC模式簡介 MVC(Model View Control)模型-視圖-控制器 首先我們需要知道MVC模式並不是javaweb項目中獨有的,MVC是一種軟體工程中的一種軟體架構模式,把軟體系統分為三個基本部分:模型(Model)、視圖(View)和控制器(Controller),即為MV ...
  • 搶購、秒殺是平常很常見的場景,面試的時候面試官也經常會問到,比如問你淘寶中的搶購秒殺是怎麼實現的等等。 搶購、秒殺實現很簡單,但是有些問題需要解決,主要針對兩個問題: 1 高併發對資料庫產生的壓力 2 競爭狀態下如何解決庫存的正確減少("超賣"問題) 第一個問題,對於PHP來說很簡單,用緩存技術就可 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...