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


  狀態管理和上一章的訂閱發布都算是Dapr相較於其他服務網格框架來講提供的比較特異性的內容,今天我們來講講狀態管理。

目錄:
一、通過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授權  && 百度版Oauth2

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

十一、通過Dapr實現一個簡單的基於.net的微服務電商系統(十一)——一步一步教你如何擼Dapr之自動擴/縮容

十二、通過Dapr實現一個簡單的基於.net的微服務電商系統(十二)——istio+dapr構建多運行時服務網格 

十三、通過Dapr實現一個簡單的基於.net的微服務電商系統(十三)——istio+dapr構建多運行時服務網格之生產環境部署

十四、通過Dapr實現一個簡單的基於.net的微服務電商系統(十四)——開發環境容器調試小技巧

十五、通過Dapr實現一個簡單的基於.net的微服務電商系統(十五)——集中式接口文檔實現

十六、通過Dapr實現一個簡單的基於.net的微服務電商系統(十六)——dapr+sentinel中間件實現服務保護

十七、通過Dapr實現一個簡單的基於.net的微服務電商系統(十七)——服務保護之動態配置與熱重載

附錄:(如果你覺得對你有用,請給個star)
一、電商Demo地址

二、通訊框架地址

  什么是狀態?簡單來講就是數據狀態。比如我訪問/api/user/1,返回{userid:1,name:xiaoming},無論我的實例有多少個,我通過接口訪問這個url都能夠得到該條信息。一般的設計中我們的應用是無狀態的,所謂無狀態就是每一個實例並不握持狀態(排除緩存的情況),而是通過第三方組件可能是緩存組件也可能是數據庫來維持狀態。數據庫維持狀態這個大家都比較熟悉了畢竟都是靠CRUD起家的。另外一種則就是緩存狀態,緩存狀態有多種方式,最簡單以及最熟悉的就是我們asp.net的session以及system.cache。到了.netcore時代,微軟給我們很貼心的提供了Extensions.Caching.xxx來對我們的緩存提供一些外部支持(雖然在fx時代也有,不過相對比較麻煩)。而到了dapr,則對其提供了更進一步的支持包括更廣泛的組件支持列表、非介入性SDK集成(可直接通過http訪問)。通過這樣的方式讓我們的服務很容易對外提供並發安全的、一致性的狀態體驗。

  狀態管理和上一章講到的訂閱發布一樣,主要是依賴於Dapr強大的Component來連接Dapr適配的各種各樣的緩存中間件,同時對上層(應用)抽象為一組rest api作為讀/寫操作入口,它的讀寫操作格式如下(僅列出部分,完整的API參考這里):

GET http://localhost:<daprPort>/v1.0/state/<storename>/<key>
POST http://localhost:<daprPort>/v1.0/state/<storename>
DELETE http://localhost:<daprPort>/v1.0/state/<storename>/<key>

  state代表我們將調用dapr的狀態服務,storename則是我們申明的類型為state的component,key則是我們需要存取到redis的kv鍵值對(值在post body中以json格式發送)

  一份標准的狀態component如下(此處依然以redis為例,查看這里是所有支持列表):

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: statestore
spec:
  type: state.redis
  version: v1
  metadata:
  - name: redisHost
    value: redis.infrastructure.svc.cluster.local:6379
  - name: keyPrefix
    value: none

  選擇Dapr為我們托管狀態管理的好處是什么呢?1、我們屏蔽了技術復雜性,避免了在基礎設施層去集成各種類型的狀態中間件SDK,2、Dapr為我們實現了分布式並發和數據一致性,具體來講在並發控制方面Dapr提供了一套OCC樂觀並發控制機制,通過附加的etag來做版本校驗確保用戶回寫過程和服務器端的版本一致才能操作。3、dapr為我們提供了bulk批處理,可以批量插入/刪除數據,這部分demo沒有涉及,大家可以看看這里

  同樣的我們來看看代碼,狀態管理相較比較簡單,首先我們還是打開之前的解決方案,在RPC項目里創建一個model,該model繼承一個StateStore,主要是強制規范統一命名必須包含key,data。

    public class TestState : Oxygen.Client.ServerSymbol.Store.StateStore
    {
        public TestState()
        {
            Key = "TestState";
        }
        public override string Key { get; set; }
        public override object Data { get; set; }
    }

  接着我們再在ClientCallService的構造函數引入IStateManager依賴,同時在Call方法中我們寫入一個狀態(其他代碼隨上一章內容不變)

        private readonly IServiceProxyFactory serviceProxyFactory;
        private readonly IStateManager stateManager;
        public ClientCallService(IServiceProxyFactory serviceProxyFactory, IStateManager stateManager) {
            this.serviceProxyFactory = serviceProxyFactory;
            this.stateManager = stateManager;
        }

        public async Task<dynamic> Call()
        {
            var result1 = new OutDto();
            var result2 = new OutDto();
            var remoteService = serviceProxyFactory.CreateProxy<IHelloService>();
            await stateManager.SetState(new TestState() { Data = new OutDto() { Word = "123" } });try
            {
                 result1 = await remoteService.HelloWorld();
                 result2 = await remoteService.HelloWorldByName(new InputDto() { Name = "xiaoming" });
            }
            catch(Exception e)
            {

            }
            return new { result1, result2 };
        }

  接着我們在servicesample打印出來:

            var result = await stateManager.GetState<OutDto>(new TestState());
            Console.WriteLine(result.Word);

  啟動項目,打開postman訪問並打印控制台,可以看到狀態被正確的從clientsaample寫入,並從servicesample讀取打印到了控制台上(這里注意如果不想狀態被其他服務讀寫也就是僅能在當前服務的scope內被讀寫可以在設置component時刪除keyPrefix節即可)

 

   狀態管理就講到這里,整體使用上比較簡單,開發者只需要考慮持久化設備的可用性以及可擴展性,其他都可以交給Dapr即可。

  今天補一個小的功能點,在oxygen框架中我為AOP提供了一個入口,可以在ConfigureServices時通過LocalMethodAopProvider這個靜態類的RegisterPipelineHandler方法注冊請求前、方法前、方法后、方法異常四個匿名委托。請求前主要是注入了一個OxygenHttpContextWapper的包裝器類,該類包含了原始請求中的path/header/cookie等等原始data,並提供了一個當前請求的ILifetimeScope用於用戶進行對象注入。在方法前則提供了一個object類型的入參,方便用戶做方法前校驗。方法后則是攔截的方法體返回的result。而異常則是方法內拋出的所有unhandle異常都會被這個委托捕獲,方便用戶統一處理。

 

   今天的分享就到這里,歡迎大家評論區留言交流,歡迎對github上star+fork~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM