Hero Image
golang pprof 实战

golang pprof 实战 炸弹程序 package main import ( // 略 _ "net/http/pprof" // 会自动注册 handler 到 http server,方便通过 http 接口获取程序运行采样报告 // 略 ) func main() { // 略 runtime.GOMAXPROCS(1) // 限制 CPU 使用数,避免过载 runtime.SetMutexProfileFraction(1) // 开启对锁调用的跟踪 runtime.SetBlockProfileRate(1) // 开启对阻塞操作的跟踪 go func() { // 启动一个 http server,注意 pprof 相关的 handler 已经自动注册过了 // /debug/pprof/ if err := http.ListenAndServe(":6060", nil); err != nil { log.Fatal(err) } os.Exit(0) }() // 略 } http://localhost:6060/debug/pprof/ 类型 描述 备注 allocs 内存分配情况的采样信息 可以用浏览器打开,但可读性不高 blocks 阻塞操作情况的采样信息 可以用浏览器打开,但可读性不高 cmdline 显示程序启动命令及参数 可以用浏览器打开,这里会显示 ./go-pprof-practice goroutine 当前所有协程的堆栈信息 可以用浏览器打开,但可读性不高 heap 堆上内存使用情况的采样信息 可以用浏览器打开,但可读性不高 mutex 锁争用情况的采样信息 可以用浏览器打开,但可读性不高 profile CPU 占用情况的采样信息 浏览器打开会下载文件 threadcreate 系统线程创建情况的采样信息 可以用浏览器打开,但可读性不高 trace 程序运行跟踪信息 浏览器打开会下载文件,本文不涉及,可另行参阅《深入浅出 Go trace》 排查 CPU 占用过高

Hero Image
在 Bash 中解析命令列參數

在 Bash 中解析命令列參數 getopts getopts optstring opt [arg ...] #!/bin/bash while getopts 'abc:h' opt; do case "$opt" in a) echo "Processing option 'a'" ;; b) echo "Processing option 'b'" ;; c) arg="$OPTARG" echo "Processing option 'c' with '${OPTARG}' argument" ;; ?|h) echo "Usage: $(basename $0) [-a] [-b] [-c arg]" exit 1 ;; esac done shift "$(( $OPTIND -1 ))" optstring 代表支援的選項。若某個選項需要參數,則在它後面加冒號 (:)。例如選項 c 需要參數,會寫成 c: 當選項有關聯參數時,getopts 會將參數字串存到 OPTARG shell 變數中。例如 option c 的參數會存到 OPTARG。 opt 包含已解析的選項。 #!/bin/bash while getopts ':abc:h' opt; do case "$opt" in a) echo "Processing option 'a'" ;; b) echo "Processing option 'b'" ;; c) arg="$OPTARG" echo "Processing option 'c' with '${OPTARG}' argument" ;; h) echo "Usage: $(basename $0) [-a] [-b] [-c arg]" exit 0 ;; :) echo -e "option requires an argument.\nUsage: $(basename $0) [-a] [-b] [-c arg]" exit 1 ;; ?) echo -e "Invalid command option.\nUsage: $(basename $0) [-a] [-b] [-c arg]" exit 1 ;; esac done shift "$(( $OPTIND -1 ))" 注意我們也更新了 optstring,現在以冒號 (:) 開頭,會抑制預設的錯誤訊息。 當 OPTERR 變數設為 0 時,getopts 會停用錯誤訊息輸出。 使用 getopt 解析長選項 #!/bin/bash VALID_ARGS=$(getopt -o abg:d: --long alpha,beta,gamma:,delta: -- "$@") if [[ $? -ne 0 ]]; then exit 1; fi eval set -- "$VALID_ARGS" while [ : ]; do case "$1" in -a | --alpha) echo "Processing 'alpha' option" shift ;; -b | --beta) echo "Processing 'beta' option" shift ;; -g | --gamma) echo "Processing 'gamma' option. Input argument is '$2'" shift 2 ;; -d | --delta) echo "Processing 'delta' option. Input argument is '$2'" shift 2 ;; --) shift; break ;; esac done -o 選項代表短選項 --long 選項代表長選項

Hero Image
Tcpdump 使用总结

Tcpdump 使用总结 命令使用 tcpdump 采用命令行方式,它的命令格式为: tcpdump [ -AdDeflLnNOpqRStuUvxX ] [ -c count ] [ -C file_size ] [ -F file ] [ -i interface ] [ -m module ] [ -M secret ] [ -r file ] [ -s snaplen ] [ -T type ] [ -w file ] [ -W filecount ] [ -E spi@ipaddr algo:secret, ... ] [ -y datalinktype ] [ -Z user ] [ expression ] tcpdump 的简单选项介绍 -E spi@ipaddr algo:secret , ...,可通过spi@ipaddr algo:secret 来解密 IPsec ESP 包。secret 为用于 ESP 的密钥,使用 ASCII 字符串方式表达。 如果以 0x 开头,该密钥将以 16 进制方式读入。 除了以上的语法格式(指spi@ipaddr algo:secret), 还可以在后面添加一个语法输入文件名字供 tcpdump 使用(即把 spi@ipaddr algo:secret, … 中…换成一个语法文件名)。 在接收到第一个 ESP 包时会打开此文件, 所以最好此时把赋予 tcpdump 的一些特权取消(可理解为,这样防范之后,当该文件为恶意编写时,不至于造成过大损害)。 -T type 强制 tcpdump 按 type 指定的协议所描述的包结构来分析收到的数据包。 目前已知的 type 可取的协议为: aodv (Ad-hoc On-demand Distance Vector protocol, 按需距离向量路由协议,在 Ad hoc(点对点模式)网络中使用), cnfp (Cisco NetFlow protocol) rpc(Remote Procedure Call) rtp (Real-Time Applications protocol) rtcp (Real-Time Applications con-trol protocol) snmp (Simple Network Management Protocol) tftp (Trivial File Transfer Protocol, 碎文件协议) vat (Visual Audio Tool, 可用于在 internet 上进行电视电话会议的应用层协议) wb (distributed White Board, 可用于网络会议的应用层协议) 实用命令实例 截获主机 210.27.48.1 和主机 210.27.48.2 或 210.27.48.3 的通信

Hero Image
iPhone 鈴聲製作教學,將 MP3 音樂換成電話鈴聲或鬧鐘鈴聲

iPhone 鈴聲製作教學,將 MP3 音樂換成電話鈴聲或鬧鐘鈴聲 影片版的 iPhone 鈴聲製作步驟 步驟一:準備想換成 iPhone 鈴聲的 MP3 音樂 首先第一步是準備好你想當成鈴聲的音樂,建議是 MP3 檔,然後儲存在「檔案 App」的資料夾內 步驟二:透過 Garageband App 製作 iPhone 鈴聲 接著,請開啟 iPhone 內建的「Garageband App」(如果你刪除了請先下載回來),點選「製作歌曲」,然後選擇「錄音機」。 點選音軌: 現在進入了錄音機的頁面,點選左上角第三個圖示進到音軌,然後再點選右上角倒數第二個圓圈圖示 將 MP3 音樂拖曳到音軌上: 這步驟很關鍵,將分頁切換到「檔案」,然後找到你剛剛下載好的 MP3 音樂,將它拖曳到左邊的音軌上。 編輯鈴聲: 接著,你可以拖拉音樂的前後來編輯你想要的鈴聲片段,也可以按播放鍵來試聽目前的鈴聲是否符合你的預期。 儲存歌曲: 確認沒問題之後,點選左上角的「三角形圖示」,然後按一下「我的歌曲」,你會看到該檔案已儲存成功,接著請長按它。 製作鈴聲: 長按該音訊檔案後,選擇「分享」,然後點選「鈴聲」。 輸出鈴聲: 而在這邊你可以編輯該鈴聲的名稱,編輯完後點選右上角的「輸出」,這樣就完成自訂 iPhone 鈴聲了! 步驟三:iPhone 電話鈴聲設定 開啟 iPhone 上的「設定」app,點選「聲音與觸覺回饋」>「鈴聲」,在鈴聲這區塊內你就會看到剛剛製作好的鈴聲囉。 步驟四:iPhone 鬧鐘鈴聲設定 開啟「時鐘 App」點選左上角的「編輯」,然後選擇任一個你想更換鈴聲的的 iPhone 鬧鐘。 點選「提示聲」後,將「鈴聲」改為你剛剛製作好的 MP3 音樂鈴聲就可以了。

Hero Image
怎么选择 Go 文件读取方案

怎么选择 Go 文件读取方案 Go 提供了可一次性读取文件内容的方法:os.ReadFile 与 ioutil.ReadFile。在 Go 1.16 开始,ioutil.ReadFile 就等价于 os.ReadFile。 一次性加载文件的优缺点非常明显,它能减少 IO 次数,但它会将文件内容都加载至内存中,对于大文件,存在内存撑爆的风险。 逐行读取 Go 中 bufio.Reader 对象提供了一个 ReadLine() 方法,但其实我们更多地是使用 ReadBytes(’\n’) 或者 ReadString(’\n’) 代替。 func ReadLines(filename string) { fi, err := os.Open(filename) if err != nil{ panic(err) } defer fi.Close() reader := bufio.NewReader(fi) for { _, err = reader.ReadString('\n') if err != nil { if err == io.EOF { break } panic(err) } } } 块读取 块读取也称为分片读取,这也很好理解,我们可以将内容分成一块块的,每次读取指定大小的块内容。这里,我们将块大小设置为 4KB。 func ReadChunk(filename string) { f, err := os.Open(filename) if err != nil { panic(err) } defer f.Close() buf := make([]byte, 4*1024) r := bufio.NewReader(f) for { _, err = r.Read(buf) if err != nil { if err == io.EOF { break } panic(err) } } } result BenchmarkOsReadFile4KB-8 92877 12491 ns/op BenchmarkOsReadFile4MB-8 1620 744460 ns/op BenchmarkOsReadFile4GB-8 1 7518057733 ns/op signal: killed BenchmarkReadLines4KB-8 90846 13184 ns/op BenchmarkReadLines4MB-8 493 2338170 ns/op BenchmarkReadLines4GB-8 1 3072629047 ns/op BenchmarkReadLines16GB-8 1 12472749187 ns/op BenchmarkReadChunk4KB-8 99848 12262 ns/op BenchmarkReadChunk4MB-8 913 1233216 ns/op BenchmarkReadChunk4GB-8 1 2095515009 ns/op BenchmarkReadChunk16GB-8 1 8547054349 ns/op 在本文的测试条件下(每行数据 1KB),对于小对象 4KB 的读取,三种方式差距并不大;在 MB 级别的读取中,直接加载最快,但块读取也慢不了多少;上了 GB 后,块读取方式会最快。

Hero Image
fortios_system_config_backup_restore 的拼寫錯誤、缺少 collection,或模組路徑不正確

fortios_system_config_backup_restore 的拼寫錯誤、缺少 collection,或模組路徑不正確 問題 Hi, 我在嘗試使用 fortios_system_config_backup_restore 模組,並依照你的 playbook 範例從 Fortigate 取得設定。 我使用的是 ansible 2.10.6。 當我使用 fortinet.fortios:1.1.8 這個 collection 時,出現以下錯誤:missing 1 required positional argument: 'mod' The full traceback is: Traceback (most recent call last): File "/home/ansible/.ansible/tmp/ansible-local-8668osvgufxk/ansible-tmp-1615481963.0092971-8768-3877705280026/AnsiballZ_fortios_system_config_backup_restore.py", line 102, in <module> _ansiballz_main() File "/home/ansible/.ansible/tmp/ansible-local-8668osvgufxk/ansible-tmp-1615481963.0092971-8768-3877705280026/AnsiballZ_fortios_system_config_backup_restore.py", line 94, in _ansiballz_main invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS) File "/home/ansible/.ansible/tmp/ansible-local-8668osvgufxk/ansible-tmp-1615481963.0092971-8768-3877705280026/AnsiballZ_fortios_system_config_backup_restore.py", line 40, in invoke_module runpy.run_module(mod_name='ansible_collections.fortinet.fortios.plugins.modules.fortios_system_config_backup_restore', init_globals=None, run_name='__main__', alter_sys=True) File "/usr/lib/python3.8/runpy.py", line 207, in run_module return _run_module_code(code, init_globals, run_name, mod_spec) File "/usr/lib/python3.8/runpy.py", line 97, in _run_module_code _run_code(code, mod_globals, init_globals, File "/usr/lib/python3.8/runpy.py", line 87, in _run_code exec(code, run_globals) File "/tmp/ansible_fortinet.fortios.fortios_system_config_backup_restore_payload_mplamrs7/ansible_fortinet.fortios.fortios_system_config_backup_restore_payload.zip/ansible_collections/fortinet/fortios/plugins/modules/fortios_system_config_backup_restore.py", line 472, in <module> File "/tmp/ansible_fortinet.fortios.fortios_system_config_backup_restore_payload_mplamrs7/ansible_fortinet.fortios.fortios_system_config_backup_restore_payload.zip/ansible_collections/fortinet/fortios/plugins/modules/fortios_system_config_backup_restore.py", line 436, in main TypeError: __init__() missing 1 required positional argument: 'mod' fatal: [fortigate-01]: FAILED! => { "changed": false, "module_stderr": "Traceback (most recent call last):\n File \"/home/ansible/.ansible/tmp/ansible-local-8668osvgufxk/ansible-tmp-1615481963.0092971-8768-3877705280026/AnsiballZ_fortios_system_config_backup_restore.py\", line 102, in <module>\n _ansiballz_main()\n File \"/home/ansible/.ansible/tmp/ansible-local-8668osvgufxk/ansible-tmp-1615481963.0092971-8768-3877705280026/AnsiballZ_fortios_system_config_backup_restore.py\", line 94, in _ansiballz_main\n invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n File \"/home/ansible/.ansible/tmp/ansible-local-8668osvgufxk/ansible-tmp-1615481963.0092971-8768-3877705280026/AnsiballZ_fortios_system_config_backup_restore.py\", line 40, in invoke_module\n runpy.run_module(mod_name='ansible_collections.fortinet.fortios.plugins.modules.fortios_system_config_backup_restore', init_globals=None, run_name='__main__', alter_sys=True)\n File \"/usr/lib/python3.8/runpy.py\", line 207, in run_module\n return _run_module_code(code, init_globals, run_name, mod_spec)\n File \"/usr/lib/python3.8/runpy.py\", line 97, in _run_module_code\n _run_code(code, mod_globals, init_globals,\n File \"/usr/lib/python3.8/runpy.py\", line 87, in _run_code\n exec(code, run_globals)\n File \"/tmp/ansible_fortinet.fortios.fortios_system_config_backup_restore_payload_mplamrs7/ansible_fortinet.fortios.fortios_system_config_backup_restore_payload.zip/ansible_collections/fortinet/fortios/plugins/modules/fortios_system_config_backup_restore.py\", line 472, in <module>\n File \"/tmp/ansible_fortinet.fortios.fortios_system_config_backup_restore_payload_mplamrs7/ansible_fortinet.fortios.fortios_system_config_backup_restore_payload.zip/ansible_collections/fortinet/fortios/plugins/modules/fortios_system_config_backup_restore.py\", line 436, in main\nTypeError: __init__() missing 1 required positional argument: 'mod'\n", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1 } 使用最新的預發布版 fortinet.fortios:2.0.0 時,我得到: