發表文章

Grafana K6

圖片
Grafana K6 最近工作需要做壓力測試, 由於 api 有做自定義的加密 在挑選壓力測試工具的時候就先想到了 k6 安裝 K6 mac: brew install k6. 其餘的可以參考這裡: Installation 使用 K6 撰寫 壓力測試腳本 基本的入門測試可以參考網路上其他大神寫的文章 或是參考這裡: Running K6 這裡主要介紹, 如果要透過額外寫 Node.js 的邏輯上去該怎麼處理。 因為 K6 底層是由 Go 撰寫而成的,js 只是對應的介面, 所以要加入 Node.js 邏輯要額外透過 Webpack 處理! 步驟 0 : 先建立對應的目錄 mkdir . / example - project && \ cd "$_" && \ npm init - y 步驟 1 : 安裝會用到的工具 npm install -- save - dev \ webpack \ webpack - cli \ @types / k6 \ babel - loader \ @babel / core \ @babel / preset - env \ core - js 步驟 2 : 設定 webpack.config.js const path = require ( 'path' ) ; const webpack = require ( 'webpack' ) ; // 這是新增的,要引入 webpack。 module . exports = { mode : 'production' , entry : { login : './src/login.test.js' , signup : './src/signup.test.js' , } , output : { path : path . resolve ( __dirname , 'dist' ) , // eslint-disable-line li...

Three.js 觀念介紹

要去呈現 three.js 的畫面需要至少這三個要素 scene (場景) camera (攝影機) renderer (渲染器) 產生物件三要素 geometry: three.js 中的物件, 包含所有的點跟面 material: 幫 geometry 加上顏色 mesh: 把 material 應用到 geometry 上面,可以直接把 mesh 放到 scene 中,讓 mesh 可以在 scene 中自由的移動 const geometry = new THREE.BoxGeometry( 1, 1, 1 ); const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } ); const cube = new THREE.Mesh( geometry, material ); scene.add( cube ); camera.position.z = 5; 上面程式碼的意思是產生一個 BoxGeometry 產生一個 0x00ff00 顏色的 material 產生一個可以放在 scene 中的 mesh, mesh 將 geometry 與 material 組合成一個可以在場景中自由控制的物件,並加入到 scene 中

MySQL - Virtual Column

圖片
Virtual Columns in InnoDB INFORMATION_SCHEMA 記錄了一些關於 InnoDB 管理的 schema 物件的 metadata, 這些資訊來自於 InnoDB 內部 system tables, 這些資訊沒辦法跟一般 table 一樣, 可以直接查詢, 傳統上的做法應該是解析 SHOW_ENGINE_INNODB_STATUS 的輸出. 不過 INFORMATION_SCHEMA 這張表有提供介面可以讓你使用 SQL 查詢這類型的資料. 這個跟 Virtual Column 有什麼關係?  Virtual Column 其實並不會儲存實體資料在 table 的 clustered index 內! 不過 Virtual Column 的 metadata 會存在 InnoDB 的 INFORMATION_SCHEMA  的 SYS_COLUMNS 內! 舉例來說 ## 建立一張表 t 有著 a, b, c 三個欄位, c 是 virtual column CREATE TABLE t (a INT, b INT, c INT GENERATED ALWAYS AS(a+b), PRIMARY KEY(a)); ## SELECT * FROM t; +----+------+------+ | a | b | c | +----+------+------+ | 11 | 3 | 14 | +----+------+------+ ## 從 SYS_COLUMNS 中觀察 SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS WHERE TABLE_ID IN ( SELECT TABLE_ID FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE "t%" ); +----------+------+-------+-------+--------+-----+ | TABLE_ID | NAME | POS | MTYPE | PRTYPE | LEN | +----------+------+-------+-------+--------+...

CORS - Cross-Origin Resource Sharing 跨來源資源共用

關於 CORS 最簡單的理解大概是在 A 網域的頁面呼叫了 B 網域的資源 時,會發出的跨網域請求。只要是不同的 網域 、 PORT 、 通訊協定 ,通通都算跨網域。 基於安全性考量,程式碼所發出的跨網域 HTTP 請求 (XMLHttpRequest, Fetch),一樣也會受到 same origin policy 的限制,必須在同個網域內,否則一樣使用 CORS 的請求。 會需要注意 CORS 的 Request: XMLHttpRequest, Fetch 網頁字體 (跨網域的 css 裡面的 @font-face) WebGL 的 texture drawImage 用到的圖片 or video frames css 這裡就不多寫關於 Simple Request 與 Preflighted requests,可以直接參考 MDN  的網站。 不過當遇到 Preflighted Request 的時候有些要注意的事情。 WebKit Nightly 與 Safari Technology Preview 對 Accept、Accept-Language (en-US) 及 Content-Language (en-US) 標頭值加入了額外的限制。假如這三個 header 中有任一個擁有「非標準」值,WebKit/Safari 就不會將該請求視為 Simple Request header('Content-Type: application/json; charset=utf-8'); header('Access-Control-Allow-Origin: http://abc.com'); header('Access-Control-Allow-Methods: POST, GET, DELETE, PUT, PATCH, OPTIONS'); header('Access-Control-Max-Age: 86400'); header("Access-Control-Allow-Headers: Content-Type, Accept"); 以上述來說, 如果只想允許 http://abc.com 的網域過來的請求, 就在 Access-Control-Allo...

System Design - DNS

圖片
DNS 階層 DNS 並不是單一伺服器,而是整個基礎架構,由一堆 name servers 在不同的階層中 在 DNS 階層中,主要有分成四個類型的伺服器類型 DNS Resolver (Recursive Resolver): 作用是接收如網頁瀏覽器、應用程式等的查詢,並將請求轉發給其他 DNS name servers Root-level name servers: 維護 top-level domain, ex:    .com  ,    .edu  ,    .us  ,  .io  等等。舉例來說,當你查詢 maper.io 的 IP 時,root-level name servers 會回傳一個擁有 .io 的 top-level domain name server 的 IP 地址列表給你。更簡單來說,root-level name servers 會告訴你 .io 要去哪個 top-level domain name server 中找,有點像是索引的概念。 Top-level domain name servers: 這些伺服器有著 authoritative name servers 的 ip。 Authoritative name servers: Authoritative name servers 是 name servers 查詢中的最後一站。如果 Authoritative name servers 能夠存取請求的記錄,則其會將已請求主機名稱的 IP 位址傳回到發出初始請求的 DNS 解析程式,也就是回傳網頁/應用程式的主機 ip。 Iterative vs recursive query resolution 有兩個執行 DNS query 的方式 Iterative: 本地端向本地/ISP, root, top-level domain, authoritative name servers 依序請求 ip 位置。 Recursive: 本地 -> root -> top-level-domain -> authoritative -> top-level-domain -> ...

Linux 事件驅動筆記

圖片
 I/O Model Synchronous I/O Blocking Non-Blocking I/O multiplexing Asynchronous I/O Blocking 跟 Non-Blocking 差異只差在 選擇 ! Blocking 以 read (read from a file descriptor) 來舉例, 從 user space 發出 read (kernel提供的 system call) 之後, 這時候就會切換到 kernel mode,kernel 會依據給定的 file descriptor 去判斷, 這個 fd 來自哪裡,接下來等待資料,因為 kernel space 跟 user space 本身就是 isolated, 這樣在 user space 的 process crash,也不會影響到 kernel space, 所以 kernel space 拿到資料之後,因為 isolated 的關係,要將資料複製到 user space 去。 在這個過程中,user space 的 read 基本上就是一直在等結果。 read 如果失敗會有 err number 可以注意 EAGAIN EWOULDBLOCK Non-blocking 就是類似一直來問 read 目前的狀態, kernel 回到 user space 可能裝置還沒準備好,或是要等之後的操作才會生效, 這時候就會發出 EAGAIN 的錯誤,EAGAIN 不代表是真的錯誤,再試一次可能就可以, I/O Multiplexing (這個邏輯跟數位邏輯的 mux 很像,故取做 IO multiplexing) multiplexing => 有多個輸入(input), 可以透過一個 select 去決定輸出 假設 Linux 要等待很多種資料, 就可以用這個概念,去監控哪個 fd 有資料, 有資料的話就挑選出來! 所以 I/O Multiplexing 本質還是 blocking,只是可以一次監聽多個 所以像網頁伺服器要監聽很多個 incoming request,就可以用這種方式處理 select 單個 process 可以被監聽的 fd 數量有限制 (跟這個 /proc/sys/fs/file-max 有關) 因為是一個一個詢問(輪詢),所以監聽...

[Laravel] Custom guard and auth provider

圖片
前言 如果要客製自己的 auth gard 用來處理驗證與登入 首先可以從官網的 Authentication 中找到! 但是寫的有一點點不全面,在這邊重新整理一下。 如果是要用 jwt 登入這種,則可以直接參考官網即可! 大致需要 自己定義的 Auth Guard 自己定義的 User Provider (後面解釋) 用來驗證的 model 建立用來驗證的 model <?php namespace App\Models\Member; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Foundation\Auth\User as Authenticatable; class Member extends Authenticatable { use SoftDeletes; protected $table = 'members'; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'name', 'email', 'password', 'cell_phone', 'verified', 'status', 'facebook_id', 'line_id', ]; /** * The attributes that should be hidden for arrays. * * @var array */ protected $hidden = [ 'password', ]; protected $dates = [ 'deleted_at', ]; } 在這邊我主要是先建立一個 Member.php 的 model 這裡有些...

[Nodejs] npm install 時跑出錯誤

在 Ubuntu 20.04, Node version: 16.13.0 在安裝 opecc 出噴出一堆錯誤,原本以為是 npm WARN deprecated node-pre-gyp@0.14.0: Please upgrade to @mapbox/node-pre-gyp: the non-scoped node-pre-gyp package is deprecated and only the @mapbox scoped package will recieve updates in the future 這個警告造成無法安裝,但更新之後一樣無法安裝 最好詳細追查錯誤 log 看到底下: 1555 error /bin/sh: 1: python: not found 大致猜測是 20.04 預設沒有 python, 而是 python3 所以用 ln -s /usr/bin/python3 /usr/bin/python 之後 重新執行 npm i 就可以安裝囉!

非同步模型筆記

Concurrency: 兩件以上的事情,同時被一個處理單位處理,以分時的方式。 ex: 處理A事情處理到一半,把 call stack 丟出去,載入 B stack 到暫存器中,以分時的方式處理。 Parallelism: 多個事件,被多個處理單位同時處理。 這兩種程式在開發的時候都非常困難,因為有 shared memory 的問題! Shares memory 會造成 1. Race condition 2. Dead lock 解決方式 1. functional programing - 每件事都是 immutable 2. Actor model - 把 mutable 的狀態封裝在物件內,只透過非同步的通訊方式交換訊息 Actor 1. 輕量化的物件,有自己內部可改變的 state,別人不可改,也不共享 2. 跑在自己的執行緒上面 3. 沒有 shared memory state 4. 別的 actor 來的訊息,會按照順序存在 mailbox 中,依序處理 5. 只能透過訊息改變其他 actor 6. 程式變得更可擴展,因為更輕量且每個 call stack 都很小 CSP Model Actor vs CSP 相同: 1. 不同的執行單元是透過傳 message 的方式溝通 2. 他們自己內部都有 private state,所以不需要 lock 3. 他們不是用共享記憶體的方式通訊,而是通訊來達到共享記憶體 不同: 1. CSP 不關注 Process 本身,所以 CPS 的 processes are anonymous,然而每個 Actor 都會有自己的身份 2. Actor 都是用非同步的方式傳送訊息,但是 CSP 則是同步,也就是 CSP 會 blocking Asynchronous model callbacks: 當相依的事件做完之後,會呼叫下一件要做的事情 會有 callback hell 的問題 promise => async/await: promise 底層其實也是透過 callback, 只是將 callback 封裝在內部, 搭配內部 state (fulfilled, pending, reject) 的管理,將 callback hell 的問題解決。 更詳細的解說請參考:  https://zhu...

[ReactNative] react-native run ios 出錯

由於最近想學 React Native,所以便從官方文件去建置環境,但發現會出現一堆問題類似下面的 ** BUILD FAILED ** The following build commands failed: Ld /Users/xxx/Library/Developer/Xcode/DerivedData/AwesomeProject-ardlldkqvtvwnthjzmutsniznwjh/Build/Products/Debug-iphonesimulator/AwesomeProject.app/AwesomeProject normal x86_64 (1 failure) 目前對我有效的使用方式是 Podfile 也要先修正一個地方 use_flipper! 改為 use_flipper!({ 'Flipper-Folly' => '2.3.0' }) 再來是底下步驟: 1. Node.js 環境升到最新版 (目前是v15.10.0) 2. 開啟 Xcode 清除專案 # Xcode 的 Product 選項 # Clean Build Folder # 註:有人有提供需要在 File > Workspace Settings > Build System ## 從 New Build System 改為 Legacy Build System ## 但對我無效,所以我最後改回 New Build System 3. 移除一些檔案並重裝 rm -rf ~/Library/Caches/CocoaPods cd 專案路徑/ios rm -rf Pods rm -rf ~/Library/Developer/Xcode/DerivedData/* pod deintegrate pod setup pod install cd 專案路徑 rm -rf node_modules npm install # 有 Podfile.lock 也記得一起移除 4. 重新啟動 Metro server (佔用一個 terminal) npm start "--reset-cache" 5. 重新執行 npx react-native run-ios 資料來源: https...

[Jenkins] 安裝 Jenkins 與Laravel在jenkins上執行測試

圖片
安裝 我這邊使用 docker 作為快速建置的方式 可以使用  https://hub.docker.com/repository/docker/neilwangtw/jenkins-php72 此為環境 PHP7.2 且 最新的 jenkins 詳細的 Dockerfile 與 docker-compose.yml 在這 https://github.com/qazwsxedccsqzse/jenkins-php72 使用方式就是先建立個目錄 /data/jenkins 接著進去裡面將 docker-compose.yml 啟起來 docker-compose up -d jenkins 預設是使用 8080 port 接下來就是去 web 介面設定 一開始在 /data/jenkins/secrets/initialAdminPassword 會有一組 hash 是拿來解鎖 Jenkins 的 輸入完之後 一開始可以先安裝 jenkins 推薦的 plugin 有額外需要的之後可以再裝! 到這邊就設定完了 從 bitbucket 上取得 repo 1. 先透過 docker 產生一組 ssh 的金鑰 # docker exec -it {jenkins docker id} bash # su jenkins $ cd ~ $ ssh-keygen 這時候就金鑰就會在實體主機的 /data/jenkins/.ssh 公鑰: /data/jenkins/.ssh/id_rsa.pub 私鑰: /data/jenkins/.ssh/id_rsa 註: 如果遇到權限問題,可以先把 /data/jenkins 的權限設定到 777 或是先在 docker 內部產生一個檔案,看一下對應實體主機, 所產生的 user 與 group 為何,我自己這邊產生的是 tss:kvm 2. 先設定用來可以存取 bitbucket 的密鑰  在 Repository Settings 內有 Access keys 或是直接到 https://bitbucket.org/組織/專案名稱/admin/access-keys/ 去新增 jenkins 的 ssh 公鑰 這個設定完就代表 jenkins 這個用戶可...

[演算法] KMP

KMP演算法是在一段文字中,找出指定的子字串出現位置(substring search)的演算法 比較詳細的說明我就不闡述,把資料留在文末。 名詞定義一下: 在一段文字中的文字,假設叫做 text 要搜尋的子字串,假設叫做 pattern 在 text 中比對到的位置使用 i, 在 pattern 中比對的位置使用 j Prerequisites 製作出 prefix table 什麼是 Prefix table Prefix table 是這個 pattern 字串所有的子字串的最長前後綴的表 舉例: pattern = ABCDABD 各個子字串的最長前後綴 子字串 前綴 (prefix) 後綴 (prefix) 最大公前後綴字串長度 A 空 空 0 AB A B 0 ABC A,AB C,BC 0 ABCD A,AB,ABC D,CD,BCD 0 ABCDA A ,AB,ABC,ABCD A ,DA,CDA,BCDA 1 ABCDAB A, AB ,ABC,ABCD,ABCDA B, AB ,DAB,CDAB,BCDAB 2 這時候就可以把最大公前後綴字串長度變成程式在用的模式 pattern A B C D A B D 0 0 0 0 1 2 0 -1 0 0 ...

[Linux] SSH Tunnel

前情提要 由於中華電信最近除了海底纜線斷掉之外,連內部路由都有問題,造成部分用戶的 socket 會連不到我們架設的伺服器,於是想到把自建的 socket server 從機房中複製一份到 GCP 上面。 但由於安全性的問題,資料庫是在機房內網,且沒有對外 IP,還有 redis 也是在機房內網,同樣沒有對外 IP,這時候該怎麼辦? 厲害同事介紹了一招,SSH Tunnel。 SSH Tunnel 單純就是幫忙做 Port Forwarding。 假設我現在我有台主機 A,需要連線到內網的資料庫,但只有主機 B 才可以直接透過內網連線到資料庫,則我們可以透過 SSH Tunnel 將內網資料庫的 3306 port,對應到主機 A 的自定義 port,流量則是透過主機 B 轉給內網的資料庫。 定義一下名詞: 主機 A => socket server 主機 B => ap 資料庫 => db 1. 先在 db 內開一個專門用來 ssh 的帳號,假設叫 tunneluser 2. 在 db 開的 tunneruser 的 ~/.ssh/authorized_keys 內新增 socket server 的 public key 3. 在 ap 內開一個專門用來 ssh 的帳號,假設叫 tunneluser 4. 在 ap 開的 tunneruser 的 ~/.ssh/authorized_keys 內新增 socket server 的 public key 5. 接下來在 socket server 上的 ~/.ssh/config內新增 Host ap HostName 1.2.3.4 User tunneluser Port 22 IdentityFile ~/.ssh/id_rsa Host db HostName 2.2.3.4 Port 22 User tunneluser ProxyCommand ssh -q -W %h:%p ap IdentityFile ~/.ssh/id_rsa 6. 接著在 socket server 中輸入 nohup ssh -N -L 3306:localhost:3306 db & nohup 跟後面的 & 是為了把 ssh tunnel 放在背景持續執行 第一個 3306 是 so...

[MySQL] 8.0 replica

最近剛好需要幫公司的資料庫做 replica, 但由於之前的資料庫沒有開啟 binlog, 所以研究了一下該怎麼操作。 如果是剛開始建立服務,建議 binlog 的設定要記得打開,如果沒有打開的話,變成要實作 replica 就需要先將資料備份出來,然後在備份出來的 master 資料還原給 slave,之後再去開啟 master 的 binlog,與建立要給 slave 同步用的帳號。 稍微解釋一下主從式架構,主要是由 master 來執行讀與寫,然後每個操作會記錄在 binlog 中,master 會透過 REPLICATION 這個權限讓 slave 可以去取回 binlog 的操作,藉由非同步的方式同步資料。 預先提醒,如果 slave 是由 master 透過複製虛擬機出來的,如果遇到 Last_IO_Error: Fatal error: The slave I/O thread stops because master and slave have equal MySQL server UUIDs;  these UUIDs must be different for replication to work 這個錯誤,就是代表 MySQL Server 的 UUID 重複,這時候只需要把 slave 的 /var/lib/mysql/auto.cnf 這個檔案刪除,之後執行 service mysql restart 就可以解決問題囉! Master 1. 以 Ubuntu 20.10 為例,MySQL 設定 replica 的設定檔在 /etc/mysql/mysql.conf.d/mysqld.cnf 在該檔案中加入 binlog_do_db = 指定的資料庫 bind-address = 0.0.0.0 server_id = 1 log_bin = /var/lib/mysql/mysql-bin.log log-slave-updates = 0 expire_logs_days = 10 # 如果開始 sync_binlog = 1 與innodb_flush_log_at_trx_commit # 一致性會是最好,但會影響效能。 sync_binlog = 0 innodb_flush_log_at_trx_commit = 0 ...

[MySQL] schema 與資料類型優化

圖片
選擇優化的資料類型 原則: 越小越好 因為會佔用最小的磁碟、記憶體與CPU快取。 越簡單越好 操作整數比操作字串代價低,因為字串排序規則 ex: 儲存ip應該用 unsigned int - 4 bytes, 用 varchar 會用到 15 bytes 儲存時間應該用 mysql 內建的時間類型 DATETIME, TIMESTAMP可以儲存相同資料:時間日期,精確到秒 TIMESTAMP 只用 DATETIME 一半的儲存空間,根據時區自動變化 TIMESTAMP 允許的時間範圍比 DATETIME 小很多 避免 NULL 在 innodb 上有單獨的 bit 儲存 null 值,但在 myisam,但還是盡量避免 整數類型 tinyint - 8 bits smallint - 16 bits mediumint - 24 bits int - 32 bits bigint - 64 bits 如果是有正負數的,會因為 1 bits 會用來記錄正負,故範圍為 -2^(n-1) ~ 2^(n-1) unsigned 的範圍則是 -2^n ~ 2^n MySQL 可以為整數指定寬度,例如 INT(11),其實沒什麼意義,11只是表示與 MySQL 相關工具(client 端的 cli) 用來顯示的長度,對於儲存與計算來說,INT(1)與INT(20)是一樣的。 實數類型 decimal(M,N) - M: 最大位數, N: 小數點後有幾位 ex: decimal(18, 9) => 9位數字.9位數字,總共使用 9 個 bytes float => 4 bytes double => 8 bytes decimal的計算雖然比較精確,但需要額外,但需要額外的空間與計算開銷,資料量較大時,可以用 bigint 代替 decimal,假設需要精準到萬分之一,則可以將數字*1百萬,將結果存在 bigint 內,可以同時避免福點數計算不精準與 decimal 計算代價太高。 字串類型 VARCHAR row_format=fix,這樣就都會固定長度,沒意義 varchar會需要額外1~2 bytes記錄長度, 假設用 latin1 charset, varchar(10) => 11 bytes, varchar(1000) => 1002...

[Ubuntu] vm主機做 resize 時遇到的問題

圖片
前情提要: 公司舊有主機當初用 vmware 建立時分配到 100G,然而實際上能用的只有(/dev/sda1)50G,但時間久了,容量不夠用,這時候從 vmware 介面去加大硬碟之後,一樣沒辦法將 /dev/sda1 變大。 # fdisk -l 處理方法與過程: 依照以前在 aws 上面的處理經驗,理論上是使用 growpart /dev/sda 1 resize2fs /dev/sda1 就可以解決,然侯事情不是我想的這麼簡單,過程中都出現 NO CHANGE 看起來是行不通了,於是! 查了一下各路文章發現,需要把 partition table 整個洗掉,重新建立新的 partition table。 過程: 第一件最重要的事情,就是 備份 。如果不備份,失敗的話就可以跑路了XD 再來使用指令 # fdisk /dev/sda 使用了之後,會進去 fdisk 的互動模式,接著介紹指令 p => 印出目前的指定硬碟的分割表 d => 刪除指定的分割,ex: 輸入1就代表刪除 /dev/sda1 的 partition 的位置 (使用 d 的話,後面會問你要刪除哪個硬碟裝置代號) n => 新增指定的分割,ex: 輸入1就代表新增 /dev/sda1 的 partition 的位置 (使用 n 的話,後面會問你這個新的硬碟裝置代號,sector( 磁區 ) 要從哪裡開始) w => 寫入 partition table 以下是大概會出現 moses@xxx:~$ sudo su - root@xxx:~# fdisk -l Disk /dev/sda: 150 GiB, 161061273600 bytes, 314572800 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x9e13d85c Device Boot Start End Sectors Size Id T...