go~wasm外掛的開發

张占岭發表於2024-04-03

Go和TinyGo是兩種不同的Go語言編譯器,它們之間有以下幾點區別:

  1. 目標平臺

    • Go:Go語言編譯器主要面向通用計算機平臺,如Windows、Linux、macOS等。
    • TinyGo:TinyGo專注於支援嵌入式系統和物聯網裝置等資源受限的平臺,如微控制器、嵌入式裝置、WebAssembly等。
  2. 效能

    • Go:Go編譯器生成的可執行檔案通常較大,執行速度較快,適合在通用計算機上執行。
    • TinyGo:TinyGo針對嵌入式系統做了最佳化,生成的可執行檔案更小,執行速度可能會受到一定影響,但更適合在資源受限的環境下執行。
  3. 語言特性支援

    • Go:Go語言擁有完整的標準庫和語言特性,適合構建各類應用程式。
    • TinyGo:由於針對嵌入式系統,TinyGo對部分Go語言特性和標準庫進行了裁剪,不支援所有Go標準庫,但提供了適用於嵌入式系統的替代方案。
  4. 編譯器實現

    • Go:Go編譯器是使用Go語言本身實現的。
    • TinyGo:TinyGo是一個基於LLVM的Go編譯器前端,透過LLVM將Go程式碼編譯為目標平臺的機器碼。

總的來說,Go適合構建通用計算機上的應用程式,而TinyGo則更適合用於嵌入式系統和物聯網裝置等資源受限的平臺。選擇使用哪種編譯器取決於你的目標平臺和需求。

github.com/alibaba/higress/plugins/wasm-go這個由阿里團隊開發的包,目前2024-03-01已經整合了redis,目前只在阿里mse上使用,不支援本地化使用,目前本地化envoy環境還不支援這個東西。
可關注它的sdk,github.com/higress-group/proxy-wasm-go-sdk,目前最新版是202402026號的,再更新後,應該就支援了

沒有封裝的redis命令,可以這樣使用

沒有的命令可以先用 Command(cmds []interface{}, callback RedisResponseCallback),透過 []interface{}{"set", "id", 1} 這種方式執行redis命令

重寫onHttpRequestBody之後需要設定請求體限制

  • 當你需要接收請求體時,你需要將mse->引數配置->DownstreamConnectionBufferLimits,預設是32768 byte
  • DownstreamConnectionBufferLimits:作用於閘道器連線,單條連結的buffer大小,配置後會影響吞吐和閘道器的記憶體使用
func onHttpRequestBody(ctx wrapper.HttpContext, config MyConfig, body []byte, log wrapper.Log) types.Action {

}

這句話的意思是:當配置單條連結的buffer大小時,這個配置會影響閘道器連線的吞吐量(即單位時間內處理的請求或資料量)和閘道器所使用的記憶體量。具體來說:

  • 吞吐量影響:單條連結的buffer大小會直接影響資料在閘道器連線中的傳輸速度和效率。較大的buffer大小可能會提高資料傳輸的速度,從而增加吞吐量;而較小的buffer大小可能會導致資料傳輸速度變慢,降低吞吐量。

  • 記憶體使用影響:配置單條連結的buffer大小後,會佔用一定量的記憶體空間來儲存這些buffer。如果buffer大小較大,將會消耗更多的記憶體資源;反之,如果buffer大小較小,則消耗的記憶體資源也相對較少。因此,合理配置buffer大小可以平衡吞吐量和記憶體使用之間的關係,以達到更好的效能表現。

對return types.ActionPause的理解

  • return types.ActionPause請求被阻塞後,透過proxywasm.ResumeHttpRequest()恢復執行,這樣其它外掛(filter)可以繼續執行
  • 當前方法中,如果return types.ActionPause後面還有其它程式碼,這些程式碼不會被執行,因為方法已經退出了
    如下程式碼,當eptid不為空時,執行了return types.ActionPause,及時它proxywasm.ResumeHttpRequest()了,那下面的程式碼username這塊,也不會被執行
if eid != "" {
		err := blackProcess(ctx, config, log,  != "" {, BLACKLIST_EPTID)
		if err != nil {
			log.Errorf("blackProcess error while calling redis")
			return types.ActionContinue
		}
		return types.ActionPause
	}

	if username != "" {
		err := blackProcess(ctx, config, log, username, BLACKLIST_KCUSERNAME)
		if err != nil {
			log.Errorf("blackProcess error while calling redis")
			return types.ActionContinue
		}
		return types.ActionPause
	}

以下這兩個方法定義有什麼區別

  • func (config RedisConfig) BlackProcess(ctx wrapper.HttpContext, log wrapper.Log, val string, blackType string)
  • func (config *RedisConfig) BlackProcess(ctx wrapper.HttpContext, log wrapper.Log, val string, blackType string)

這兩個方法定義的區別在於它們的接收者(Receiver)不同:

  1. func (config RedisConfig) BlackProcess(ctx wrapper.HttpContext, log wrapper.Log, val string, blackType string):這是一個針對RedisConfig型別值的方法,即使用值接收者。在呼叫該方法時,會對傳入的RedisConfig物件進行值複製,方法內部對物件的修改不會影響原始物件。

  2. func (config *RedisConfig) BlackProcess(ctx wrapper.HttpContext, log wrapper.Log, val string, blackType string):這是一個針對RedisConfig型別指標的方法,即使用指標接收者。在呼叫該方法時,會直接操作指向RedisConfig物件的指標,方法內部對物件的修改會影響原始物件。

通常情況下,如果需要在方法內部修改接收者物件的狀態或屬性,應該使用指標接收者;如果不需要修改物件狀態,只是對物件進行操作,可以使用值接收者。根據具體需求選擇合適的接收者型別來定義方法。

相關文章