通過Dapr實現一個簡單的基於.net的微服務電商系統(十)——一步一步教你如何擼Dapr之繫結

a1010發表於2021-05-13

  如果說Actor是dapr有狀態服務的內部體現的話,那繫結應該是dapr對serverless這部分的體現了。我們可以通過繫結極大的擴充套件應用的能力,甚至未來會成為serverless的基礎。最開始接觸dapr的時候,會在其官方首頁看到這麼一句話“Dapr is a portable, serverless, event-driven runtime ” 一個可移植的,伺服器的,事件驅動的執行時。可移植很容易理解,事件驅動也有所體現。那這個無伺服器(serverless)呢?今天我們就講講dapr是如何serverless的。

目錄:
一、通過Dapr實現一個簡單的基於.net的微服務電商系統

二、通過Dapr實現一個簡單的基於.net的微服務電商系統(二)——通訊框架講解

三、通過Dapr實現一個簡單的基於.net的微服務電商系統(三)——一步一步教你如何擼Dapr

四、通過Dapr實現一個簡單的基於.net的微服務電商系統(四)——一步一步教你如何擼Dapr之訂閱釋出

五、通過Dapr實現一個簡單的基於.net的微服務電商系統(五)——一步一步教你如何擼Dapr之狀態管理

六、通過Dapr實現一個簡單的基於.net的微服務電商系統(六)——一步一步教你如何擼Dapr之Actor服務

七、通過Dapr實現一個簡單的基於.net的微服務電商系統(七)——一步一步教你如何擼Dapr之服務限流

八、通過Dapr實現一個簡單的基於.net的微服務電商系統(八)——一步一步教你如何擼Dapr之鏈路追蹤

九、通過Dapr實現一個簡單的基於.net的微服務電商系統(九)——一步一步教你如何擼Dapr之OAuth2授權

十、通過Dapr實現一個簡單的基於.net的微服務電商系統(十)——一步一步教你如何擼Dapr之繫結
附錄:(如果你覺得對你有用,請給個star)
一、電商Demo地址

二、通訊框架地址

  serverless還是有必要提兩嘴,知道的同學可以直接略過。直接翻開CNCF對serverless的定義:“Serverless 是指構建和執行不需要伺服器管理的應用程式的概念”,這個概念說起來非常的大哈,實際上根據各家雲平臺提供的serverless服務來看,其主要作用是將開發者的應用程式和伺服器作業系統環境進行了隔離,讓開發人員不再關心伺服器(而不是完全不需要伺服器!),只需要通過雲函式的方式編寫特定的業務程式碼即可對外提供服務。每一個函式會被編譯成一個容器映象,當外部請求過來時Serverless會啟用這個函式執行我們的映象例項,當請求量激增時,Serverless會幫我們橫向擴容多個例項來抗住請求。當一段時間沒有請求後,Serverless又會幫我們逐步縮容雲函式例項直到例項變為0。這樣當沒有請求時的大部分時間裡雲服務商不會收取你的CPU/記憶體/網路的費用,僅僅收取一個磁碟費用(託管雲函式映象需要)。這裡面涉及到兩個問題,一個是雲函式的擴容/縮容機制,一個就是雲函式本身如何呼叫其他服務比如我要持久化資料/傳送郵件/寫簡訊/訂閱?在各家雲商提供的Serverless架構裡,擴容縮容自然是通過k8s來實現的,而呼叫外部服務則被封裝成了自家的雲服務(比如阿里雲可以呼叫RDS讀寫資料庫。呼叫OSS讀寫物件,相應的自家的Serverless架構都提供了相關函式的功能)。

  那Dapr如何實現Serverless的呢?但凡熟悉k8s的同學應該對自動化擴容、縮容這部分比較容易理解,其基於k8s的HPA機制運作,dapr通過對KEDA整合實現了這部分的功能,不過這不是今天我們要講的重點。另外一個問題,雲函式如何呼叫外部服務?這就是今天我們要講的重點——繫結機制的實現。dapr的繫結提供了非常多的外部元件訪問支援,訪問這個列表可以查詢具體的支援情況,隨著dapr的逐步迭代我相信這個列表還會逐步增加最終將覆蓋主流的大部分我們會用到的服務元件。這樣最終我們將無需和某個雲服務商的Serverless做技術繫結,只需要dapr即可實現Serverless!而我們的應用程式將會變得非常輕量級,幾乎不需要整合特定元件sdk(比如資料庫訪問sdk、sms簡訊sdk、ios訊息推送sdk等等等等)。只需要提供一個對外服務的restapi,內部完成業務操作後其餘的部分交給dapr幫我們完成即可。

  今天就來看看我們通過dapr是如何完成對資料庫訪問的,這裡依然使用我們的eshop進行舉例,在eshop中我們試著訪問我們的使用者資料庫的Account表。首先我們需要建立一個bingding型別的component,比較簡單隻需要申明這是一個bindings.postgres的Component,包含一個連結字串指向我們的infrastructure下的postgres這個k8s service。

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: accountpostgres
  namespace: dapreshop
spec:
  type: bindings.postgres
  version: v1
  metadata:
  - name: url
    value: user=postgres password=Mytestpwd#123 host=postgres.infrastructure port=5432 dbname=AccountDb sslmode=disable

  接著我們編寫程式碼來實現對該component進行訪問,通過查詢Account獲取使用者資訊並列印到postman中

  首先我們實現一個簡單的http請求用於查詢我們的繫結服務:

    public class HttpHelper
    {
        private static async Task<string> GetResultAsync(string componentName, string sql)
        {
            var req = new HttpRequestMessage(HttpMethod.Post, $"http://localhost:3500/v1.0/bindings/{componentName}");
            req.Content = new StringContent(JsonSerializer.Serialize(new { operation = "query", metadata = new { sql = sql } }));
            var resp = await new HttpClient().SendAsync(req);
            if (resp.IsSuccessStatusCode)
            {
                var result = await resp.Content.ReadAsStringAsync();
                return result;
            }
            else
                throw new NotSupportedException($"component無效或不支援的sql查詢語句");
        }
        public static async Task<List<T>> GetResultAsync<T>(string componentName, string sql) where T:class
        {
            var str = await GetResultAsync(componentName, sql);
            var obj = JsonSerializer.Deserialize<List<object>>(str);
            var result = new List<T>();
            foreach (JsonElement item in obj)
            {
                result.Add(AccountConvetor(item) as T);
            }
            return result;
        }

        static Infrastructure.PersistenceObject.Account AccountConvetor(JsonElement item)
        {
            var t = new Infrastructure.PersistenceObject.Account();
            t.Id = Guid.Empty;//由於不知名的原因uuid的鍵讀取出來的值並不是uuid而是一個陣列
            t.LoginName = item[1].GetString();
            t.Password = item[2].GetString();
            t.NickName = item[3].GetString();
            t.State = (Domain.Enums.AccountState)item[4].GetInt32();
            return t;
        }
    }

  接著在AccountQueryService中建立一個GetAccountListByDapr用於暴露該服務到外部:

        [AuthenticationFilter(false)]
        public async Task<ApiResult> GetAccountListByDapr()
        {
            var result = await HttpHelper.GetResultAsync<Infrastructure.PersistenceObject.Account>("accountpostgres", "select * from public.\"Account\"");
            return ApiResult.Ok(result);
        }

  然後我們通過postman發起一個訪問:

  可以看到成功的通過httpclient呼叫dapr獲取到了資料庫裡的資料。這裡還有些小的問題比如我的id是一個uuid格式,通過dapr讀取出來變成了一個陣列,還不知道是什麼原因。不過大體思路就是這樣了,至少目前通過dapr可以和阿里雲oss、ios訊息推送、mysql、kafka、mqtt、postgresql、rabbitmq、redis等等等等我們常用的耳熟能詳的服務/元件進行整合,而你唯一需要關心的只是通過訪問dapr的api來傳送操作/獲取資料僅此而已,dapr將元件整合的複雜度從應用層面遷移後,對於開發者來講通過dapr要實現一個serverless至少從技術層面來看已經沒有多少阻礙了。好了,今天的分享就到這裡~

相關文章