如果说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发起一个访问:

通过Dapr实现一个简单的基于.net的微服务电商系统(十)——一步一步教你如何撸Dapr之绑定-LMLPHP

  可以看到成功的通过httpclient调用dapr获取到了数据库里的数据。这里还有些小的问题比如我的id是一个uuid格式,通过dapr读取出来变成了一个数组,还不知道是什么原因。不过大体思路就是这样了,至少目前通过dapr可以和阿里云oss、ios消息推送、mysql、kafka、mqtt、postgresql、rabbitmq、redis等等等等我们常用的耳熟能详的服务/组件进行集成,而你唯一需要关心的只是通过访问dapr的api来发送操作/获取数据仅此而已,dapr将组件集成的复杂度从应用层面迁移后,对于开发者来讲通过dapr要实现一个serverless至少从技术层面来看已经没有多少阻碍了。好了,今天的分享就到这里~

05-13 23:06