Mac shell上的快捷鍵

最近看到別人分享的一篇bash shell 快捷鍵對照縮圖以後,感覺可以稍微練一下,對平常工作應該會有不少幫助XD

後來找了一下網路上的資訊,看來Apple 的官方就有放快捷鍵對照表了,決定也順便整理一下我自己的版本:

動作快速鍵Notes
重新放置插入點將游標移至新插入點的同時按住 Option 鍵
將插入點移至該行起始處Control + A
將插入點移至該行結尾處Control + E
將插入點向前移動一個字元向右鍵
將插入點向後移動一個字元向左鍵
將插入點向前移動一個單字Option + 向右鍵我的iterm2這邊要用Control + 向右鍵
將插入點向後移動一個單字Option + 向左鍵我的iterm2這邊要用Control + 向左鍵
刪除行Control + U被刪除的整列會被複製
刪除至文字行結尾處Control + K
向前刪除至文字結尾處Option + D(已選取「使用 Option 鍵作為 Meta 鍵」時可使用)無法使用
刪除前面的一個文字Control + W這個文字會被複製起來
貼上Control+W 所複製的文字Control + Y
刪除一個字元Delete 鍵
調換兩個字元的位置Control + T目前選的字元會與前面的字元對調
https://support.apple.com/zh-tw/guide/terminal/trmlshtcts/mac

References:

AWS egress 的費用

某天剛好看到了這篇文章AWS’s Egregious Egress (cloudflare.com),才知道原來AWS在頻寬這邊的計價(outgoing)真的蠻貴的,尤其是當你所用的AWS region是在一些已開發國家。

https://blog.cloudflare.com/aws-egregious-egress/
https://blog.cloudflare.com/aws-egregious-egress/

這邊算下來的數字來看,同樣的頻寬,如果是使用一般跟ISP租用每個月XX Mbps來相比,在北美這邊可以貴到約ISP 價錢的那邊的80陪。

hmmm…. 真的是蠻貴的…

雖然說AWS 的ingress是不計算費用的,但蠻多資料相關服務,其本身的egress 費用看來是無法避免的,所以這篇文章可以拿來參考一下一些AWS在營運上,頻寬費用上應該要注意的事項…

PostgreSQL 上資料插入時產生的duplicate key conflict

事發經過

起因於最近工作上遇到的一個小插曲,剛好寫完某一個服務以後,發現某一個整合測試會在特定的情況下發生錯誤。

在經過一系列的測試以後,發現整合測試的錯誤只會發生在測試資料庫剛被初始化完成時;在進一步追下去發現,每次噴出來的錯誤訊息為 ERROR: duplicate key value violates unique constraint "files_pkey",這個錯誤其實蠻奇妙的,因為這張表的id 我是讓其內部自動產生的(auto increment),但在資料庫執行一段時間以後,發現同樣的測試又可以pass了。

最後追下去發現stckoverflow上,其它人也有遇到類似的問題,照著答案中的方向去試了以後就順利解決了。

解決方案

在PostgreSQL中,如果我們設定primary key 為serial or bigserial時,PostgreSQL內部會產生一組relation用來管理對應的primary key 其下一組資料寫入時,auto increment 後的值為何。

由於我在產生測試資料時是有包含id的值,所以造成對應的那張表的id sequence誤判了當新的一筆資料要再被寫入時對應的id值,但再過了一段時間以後,PostgreSQL內部又會重新sync id sequence,所以才會有資料庫運行一段時間後,測試又可以通過了的情況。

最後的解決方案就是重新整理測試資料,讓其不包含id,所以那張表的id的管理就完全由其資料庫內部來作,自然就解決了id sequence out of sync的問題了。
(stackoverflow 文章中有另外提到其它手動的方式,來讓 primary key sequence重新對應上表的資料)

References

無所不在的SQL injection

一樣是在Hacker Daily News看到的一篇文章,作者說明了他在google上找到了30個關於php + email 註冊 的相關教學文章,發現其中的16筆是有SQL injection 的風險。

趁這個機會再來複習一下SQL Injection, 畢境這是非常常見的攻擊之 一;主要的攻擊手段是將一段有害的字串,透過網頁輸入的方式傳送至伺服器上,而伺服器的程式在沒有做任何檢查的情況下,就帶入網頁送上來的那些參數並執行了特定的SQL而造成問題。

從oswap上看到的一個典型的範例是,讓使用者在網頁端填入firstname與 lastname,然後伺服器這邊就透過使用者給的資訊來去資料庫找對應的使用者資訊,若此時使用者給的是像這樣的資訊

Firstname: evil'ex and Lastname: Newman

且執行的SQL可能會是長這樣, 其造成的問題就是會讓資料庫試著去執行evil 指令而失敗

select id, firstname, lastname from authors where firstname = 'evil'ex' and lastname ='newman'

事實上,還有更多網路上可以找到的攻擊範例,而解決方式就是在伺服器這邊需要針對使用者傳上來的資訊做更多的驗證,之後才可以使用。
另外,一些常見的web framework通常都會將這些驗證自動套用到程式中,所以如果我們有使用web framework的話,也可以看一下所使用的framework是否有對應的處理方式。

reference

Build 自己的5G network

在自家建立一個私人的網路環境已經是一個很常見的需求了,但還有一些更專業的開發者/工程師可能還會在家裡建立一個小型的企業網路,架設自己需要的伺服器與建立相對應的路由…等等。

hacker daily news 上看到一個看更酷的東西,就是架設自己的5G/mobile network,從那篇文章中列出了各個不同layer的open source 套件與相關資訊,值得注意的是文章中有提到Respberry Pi, 感覺以後有機會可以來玩看看…

reference:

Cassandra用來刪table的指令

雖然說CQL很像SQL,但在Cassandra中,用來刪table指令也是有差異的,在stackoverflow上找到下面可以用下面的指令來刪除…

TRUNCATE keyspace_name.table_name;

或是用

TRUNCATE table_name;

值得注意的是,在stackoverflow中有提到,刪table前,Cassandra預設會先對要刪的table建立一分snapshot,所以有刪table的動作的話,可能要定時清理一下舊的snoapshot。

reference:

TCP BBR

最近聽到DK提到TCP BBR這個名詞時,才知道原來它是一種新的TCP 機制,主要可以提高在網路不穩定下的TCP傳輸品質。
當下聽了覺得蠻神奇的,後來去查了以後才發現,這技術已經發表有幾年了,現在才知道真的有點感到汗顏阿0rz…

TCP BBR

TCP BBR 全名為 TCP Bottleneck Bandwidth and Round-trip propagation time,是Google 在2017年所發現的TCP 擁塞控制演算法,適用於在網路不可靠的環境下,可以有效的提升傳輸效率。

而Google他們那時也宣稱,在他們導入Youtube以後,整個infra的網路傳輸效率平均提升了4%以上。

而相關的演算法原理可以參考這裡,基本上就是控制TCP資料的傳送端,透過演算法來控制更適合的傳輸速率,進而到讓傳輸的資料速率可以到達目前傳送與接收端之間的實際最大值,也因為這樣子,所以在真實不穩定的網路下,它可以更好的讓資料傳輸量不會過大而造成網路擁塞…

設定TCP BBR

目前只要Linux Kernel 的版本大於4.9以上,就可以直接透過更改sysctl的方式來啟用目前主機上的TCP BBR,詳細的設定如下:

透過以下的設定來確定目前的tcp 擁塞演算法:

sysctl net.ipv4.tcp_available_congestion_control

在還未設定使用bbr之前,通常應該會顯示cubic

接著加入以下的設定到/etc/sysctl.conf

net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr

最後執行以下指令來套用bbr的設定

sudo sysctl -p

理論上,這時候再次用下面的指令時,目前的TCP 設定時,應該就會是bbr

sysctl net.ipv4.tcp_available_congestion_control

一些注意事項

由於TCP BBR的運作模式是主動地計算目前兩端點之前的傳輸頻寬,然後用最佳的方式去想辦法灌滿這段連線,所以從上面模式看來,要啟用的TCP BBR的機器最好是傳送資料端,這樣每次傳送時就會使用這套演算法來強化傳輸效率了。

當然,如果兩端的機器都可以啟用的話,那就沒這個問題了…

何時該套用TCP BBR呢

TCP BBR也不是萬能的,它為了提高在網路不穩定的情況下的傳輸效率,但同時也會在一些情況下,表現不如預期;這篇文章描述了一系列的情境來說明,何時套用TCP BBR會得到更好的傳輸效率。

Reference:

Go程式中的init()

在Go語言的世界裡,func init() {} 是一個適合用來初始化整個package的執行者,它會在package 第一次被import時,自動的執行其中之內容,並且它只會被執行一次…

不過使用上也必須特別注意,因為當某個package需要init 時,就代表它有一些package level variable,而這些package level variable 若是被一些內部的function 或 method 使用時,就可能造成一些side effect。

簡而言之,若使用的不好的話,是很容易造成一些anit pattern的…

舉例來說像下面這段範例程碼碼

package foo


type handler interface {
    shouldHandle() bool
    handleFoo() error
    handlerBar() error
}

type handlerImpl struct {}

func (h handlerImpl) shouldHandle() bool {
    return true
}

func (h handlerImpl) handleFoo() error {
    return nil
}

func (h handlerImpl) handleBar() error {
    return nil
}

var defaulHandler handler

func init() {
    defaultHandler = handlerImpl{}
}


func HandleFoo() error {
    if defaultHandler.shouldHandle() {
        return defaultHandler.handleFoo()
    }
    return errors.New("not allowed")
}

func HandleBar() error {
    if defaultHandler.shouldHandle() {
        return defaultHandler.handlerBar()
    }
    return errors.New("not allowed")
}

在上面這個範例中,HandleFoo, HandleBar都會先call defaultHandler.shouldHandle來看是不是需要處理接下來的流程,如果是的話,再執行各自的handle function。

如果要分別測試HandleFoo, HandleBar的話,我們就要想辦法mock defaultHandler 。 但因為defaultHandler是在init中被指派的,所以就上面的程式碼來看,是沒有直接可以測試的方式…

但如果我們不在init中指派defaultHandler,而是改用下面的範例來做的話,就可以進一步解決測試上的問題…

func Init(concreteHandler handler) {
    defaultHandler = concreteHandler
}

以這段程式碼來看,如果我們要測試HandleFoo, HandleBar的話,我們只需要在每一個unit test之前,先執行Init()來代入mocked 過的 concreteHandler就可以測試了。

不過這樣的作法是不是就沒有問題了???

很不幸的,透過Init來解決測試的問題還是會有一些副作用;由於這兩個HandleFooHandleBar 都同時用到handler.shouldHandle(),所以這也代表如果我們同時在測試這兩個function時,就會有可能發生下面的race issue:

  • test 1: 測試HandleFoo時,代入mockDefaultHandler, 並且把shouldHandle(),mock成回傳值為true.
  • test 2: 測試HandleBar時,代入mockDefaultHandler, 並且把shouldHandle(),mock成回傳值為false.

由於go test預設是會同時用多個cpu cores來執行所有的測試,這樣就會有機率性地遇到上述的問題,並發生測試結果不如預期情況…

當然如果我們直接使用go test -p 1來執行unit tests 的話就沒有race 的問題了,不過同樣的就造成測試時間變長的問題了。

寫到這邊的一些想法:

  • 如果沒有必要的話,盡量不要使用init,因為會使用init的情況通常代表這個package 有些package level variables 需要被初始化。
  • 盡量避免在func中直接使用package level variables,因為它會造成那些使用的func不易被測試。

references: