微服务架构:介绍、分布式与集群、架构四要素、设计模式、架构说明、项目结构说明、通讯方式、架构演进

参考

书籍:《ASP.NET Core 微服务实战》

微软微服务框架 dapr V1.0版本 2021-02-17 正式发布

.Net 微服务架构技术栈的那些事

Asp.Net Core微服务初体验

.NET Core微服务系列基础文章

百度百科说明: 微服务

知乎上:什么是微服务架构

微软文档:.NET 微服务 - 体系结构电子书    项目示例: eShopOnContainers GitHub

ABP微服务示例 --模块化 + ddd + 微服务 + 容器化

[Abp vNext微服务实践] - 文章目录

Blog.Core官网 -- 前后端分离(.net core + vue) + 微服务 + 容器化 + CI/CD

surging: surging作者博客   surging git地址   -- dotnetty + 微服务 + websocket-sharp + rpc + Mqtt

腾飞.NET 云原生架构师训练营笔记

分布式与集群

分布式

参考:分布式系统--百度百科

分布式就是把一个系统拆分成多个服务节点,每个节点部署在不同的服务器上,可以理解为把一个事情分为多个简单的步骤。

集群

集群就把一个服务复制部署在多台电脑上,多台电脑同时执行同一个服务节点的功能,可以理解为多个一起做同一个步骤。

集群一般需要通过分布式技术来保证数据一致和同步等问题,例如分布式事务、分布式缓存等

对称集群与非对称集群:

  • 对称集群:     集群实例角色地位相同    ,特点:数据计算
  • 非对称集群 :集群实例角色地位不相同 ,特点:数据存储,redis集群是非对称集群

微服务中先分布式后集群

先分布式:例如12306,会分成登录、查票、订单、支付等多个服务。

后集群:根据请求访问量多的服务弄成集群模式,例如12306中的查票服务。

微服务是什么

微服务是一个支持特定业务场景的独立部署单元。它借助语义化版本管理、定义良好的 API 与其他后端服务交互。它的天然特点就是严格遵守单一职责原则。

包含以下特点

  • 每个微服务独立完整性:,虽然每个微服务会有重复部分,但是不能提取出来放到公共服务中,因为要保证每个微服务都有独立性完整的功能,以便于横向集群扩展
  • 公共服务:包括注册、通信、认证、限流、负载均衡、熔断、日志等,这些公共服务有变化时不会影响到单个微服务

架构四要素:

  1. 问题:确定问题,怎么做    
  2. 问题边界 (约束 ):谁的问题,给出约束
  3. 生命周期:
  4. 拆分:根据问题的生命周期拆分

设计模式

转载自:六种微服务架构的设计模式

聚合器(常用)

这是一种最常用也最简单的设计模式,如下图所示:

聚合器调用多个服务实现应用程序所需的功能。它可以是一个简单的Web页面,将检索到的数据进行处理展示。它也可以是一个更高层次的组合微服务,对检索到的数据增加业务逻辑后进一步发布成一个新的微服务,这符合DRY原则。另外,每个服务都有自己的缓存和数据库。如果聚合器是一个组合服务,那么它也有自己的缓存和数据库。聚合器可以沿X轴和Z轴独立扩展。

异步消息传递(常用)

备注:abp的微服务demo就是使用此模式

虽然REST设计模式非常流行,但它是同步的,会造成阻塞。因此部分基于微服务的架构可能会选择使用消息队列代替REST请求/响应,如下图所示:

数据共享

自治是微服务的设计原则之一,就是说微服务是全栈式服务。但在重构现有的“单体应用(monolithic application)”时,SQL数据库反规范化可能会导致数据重复和不一致。因此,在单体应用到微服务架构的过渡阶段,可以使用这种设计模式,如下图所示:

在这种情况下,部分微服务可能会共享缓存和数据库存储。不过,这只有在两个服务之间存在强耦合关系时才可以。对于基于微服务的新建应用程序而言,这是一种反模式。

代理

这是聚合器模式的一个变种,如下图所示:

在这种情况下,客户端并不聚合数据,但会根据业务需求的差别调用不同的微服务。代理可以仅仅委派请求,也可以进行数据转换工作。

链式

这种模式在接收到请求后会产生一个经过合并的响应,如下图所示:

在这种情况下,服务A接收到请求后会与服务B进行通信,类似地,服务B会同服务C进行通信。所有服务都使用同步消息传递。在整个链式调用完成之前,客户端会一直阻塞。因此,服务调用链不宜过长,以免客户端长时间等待。

分支

这种模式是聚合器模式的扩展,允许同时调用两个微服务链,如下图所示:

微服务通讯方式

一般是:外部通信使用http,内部通信使用grpc

对微服务通讯方式RPC vs REST的理解

比较 gRPC 服务和 HTTP API

Http通信

IHttpClientFactory:组件的工厂抽象,该组件可使用自定义配置为给定逻辑名称创建 HttpClient 实例

IHttpClientFactory.CreateClient(String):使用与 name 指定的逻辑名称相对应的配置来创建和配置 HttpClient 实例。

HttpClient:提供基本类,用于发送 HTTP 请求和接收来自通过 URI 确认的资源的 HTTP 响应。

HttpClient.PostAsync(string requestUri, HttpContent content):以异步操作将 POST 请求发送给指定 URI。

HttpContent:表示 HTTP 实体正文和内容标头的基类。

StringContent(String, Encoding, String):创建 System.Net.Http.StringContent 类的新实例

HttpResponseMessage:表示包括状态代码和数据的 HTTP 响应消息。

在 ASP.NET Core 中使用 IHttpClientFactory 发出 HTTP 请求

.net core HttpClient 使用之掉坑解析(一)

核心的4行代码

private readonly IHttpClientFactory httpClientFactory;
//
HttpClient httpClient = httpClientFactory.CreateClient(String); 
//
HttpContent hc = new StringContent(String, Encoding, String); 
//
HttpResponseMessage response = await httpClient.PostAsync(string requestUri, HttpContent content);

封装好的注册通信客户端类 ConsulHttpClient 的完整代码如下:

using Newtonsoft.Json;
using RuanMou.MicroService.Core.Cluster;
using RuanMou.MicroService.Core.Registry;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace RuanMou.MicroService.Core.HttpClientConsul
{
    /// <summary>
    /// consul httpclient扩展
    /// </summary>
   public class ConsulHttpClient
   {
        private readonly IServiceDiscovery serviceDiscovery;
        private readonly ILoadBalance loadBalance;
        private readonly IHttpClientFactory httpClientFactory;
        public ConsulHttpClient(IServiceDiscovery serviceDiscovery,
                                    ILoadBalance loadBalance,
                                    IHttpClientFactory httpClientFactory)
        {
            this.serviceDiscovery = serviceDiscovery;
            this.loadBalance = loadBalance;
            this.httpClientFactory = httpClientFactory;
        }

        /// <summary>
        /// Get方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// param name="ServiceSchme">服务名称:(http/https)</param>
        /// <param name="ServiceName">服务名称</param>
        /// <param name="serviceLink">服务路径</param>
        /// <returns></returns>
        public async Task<T> GetAsync<T>(string Serviceshcme, string ServiceName,string serviceLink)
        {
            // 1、获取服务
            IList<ServiceUrl> serviceUrls = await serviceDiscovery.Discovery(ServiceName);

            // 2、负载均衡服务
            ServiceUrl serviceUrl = loadBalance.Select(serviceUrls);

            // 3、建立请求
            Console.WriteLine($"请求路径:{Serviceshcme} +'://'+{serviceUrl.Url} + {serviceLink}");
            HttpClient httpClient = httpClientFactory.CreateClient("mrico");
            // HttpResponseMessage response = await httpClient.GetAsync(serviceUrl.Url + serviceLink);
            HttpResponseMessage response = await httpClient.GetAsync(Serviceshcme +"://"+serviceUrl.Url + serviceLink);

            // 3.1 json转换成对象
            if (response.StatusCode == HttpStatusCode.OK)
            {
                string json = await response.Content.ReadAsStringAsync();

                return JsonConvert.DeserializeObject<T>(json);
            } else
            {
                // 3.2 进行自定义异常处理,这个地方进行了降级处理
                throw new Exception($"{ServiceName}服务调用错误:{response.Content.ReadAsStringAsync()}");
            }
        }

        /// <summary>
        /// Post方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// param name="ServiceSchme">服务名称:(http/https)</param>
        /// <param name="ServiceName">服务名称</param>
        /// <param name="serviceLink">服务路径</param>
        /// <param name="paramData">服务参数</param>
        /// <returns></returns>
        public T Post<T>(string Serviceshcme, string ServiceName, string serviceLink, object paramData = null)
        {
            // 1、获取服务
            IList<ServiceUrl> serviceUrls = serviceDiscovery.Discovery(ServiceName).Result;

            // 2、负载均衡服务
            ServiceUrl serviceUrl = loadBalance.Select(serviceUrls);

            // 3、建立请求
            Console.WriteLine($"请求路径:{Serviceshcme} +'://'+{serviceUrl.Url} + {serviceLink}");
            HttpClient httpClient = httpClientFactory.CreateClient("mrico");

            // 3.1 转换成json内容
            HttpContent hc = new StringContent(JsonConvert.SerializeObject(paramData), Encoding.UTF8, "application/json");

            // HttpResponseMessage response = await httpClient.GetAsync(serviceUrl.Url + serviceLink);
            HttpResponseMessage response = httpClient.PostAsync(Serviceshcme + "://" + serviceUrl.Url + serviceLink, hc).Result;

            // 3.1json转换成对象
            if (response.StatusCode == HttpStatusCode.OK || response.StatusCode == HttpStatusCode.Created)
            {
                string json = response.Content.ReadAsStringAsync().Result;

                return JsonConvert.DeserializeObject<T>(json);
            }
            else
            {
                // 3.2、进行自定义异常处理,这个地方进行了降级处理
                throw new Exception($"{ServiceName}服务调用错误:{response.Content.ReadAsStringAsync()}");
            }
        }
    }
}
View Code
 
使用HttpContext来进行微服务通信

httpcontext:封装有关单个HTTP请求的所有特定于HTTP的信息

里面有request、response、Connection 等

ASP.NET Core管道详解[2]: HttpContext本质论

 

ABP中的动态C# API客户端

要查看源码看下是使用什么通信的

RPC框架通信:rpc、grpc

参考:

花了一个星期,我终于把RPC框架整明白了!

.NET Core 上的 gRPC

gRPC 官方文档中文版

ASP.NET Core 使用 gRPC 初探 --老张的哲学

深入了解 gRPC:协议 

RPC(Remote Procedure Call):远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的思想。

 

gRPC

gRpc是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。

gRPC 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。

异步消息通信

一般是 RabbitMQ 、Kafka

分层法

以文件分层法为主,以程序集分层法为次

架构说明:

  • 网关层:路由、限流、日志、监控、负载均衡、缓存等功能
    • 负载均衡:代理多个网关,做网关集群
    • oclet:
    • 熔断降级:
    • 网关集群:
  • 认证授权层 IdentityServer4:
  • 聚合层:为页面服务,处理页面请求及给页面提供数据。
  • 服务层:各种微服务,根据功能来拆分,例如订单服务、商品服务、支付服务、认证服务等
  • 工具基础层:服务发现、熔断降级、日志、分布式事务、配置中心
    • 服务发现、注册、配置 consul:客户端发现模式、服务端发现模式、服务注册表
    • 熔断降级 Polly:
      • 熔断:作用就是在特定的场景下关掉当前的通路,从而起到保护整个系统的效果
      • 降级:保证系统核心服务正常运行,暂停非核心的一些外围服务
    • 分布式事务  Saga:保证同时操作多个服务时保持数据原子性
      • 原子性:如生成订单时要同时扣减库存,而订单和商品库存是两个服务,使用分布式事务来保证两个操作同时成功或同时失败,避免数据不一致。
    • 消息队列  CAP.RabbtMq:
    • 链路监控  SkyWalking:
    • 日志中心  Elasticsearch:
    • 数据库:SQLServer、Mysql
    • 缓存
    • 对象映射器  AutoMapper
    • Web框架  AspNetCore
    • ORM   EntityFrameworkCore
    • 通信 HTTP:

 

微服务架构图:

层次调用说明

先后顺序:【网关层】(先Nginx后到网关)=》【聚合层】=》【微服务层】=》【数据层】

【核心层 / 基础设施层】:没有先后先后顺序,因为其他服务都有都有项目引用 核心层,相当于它们的项目内都内已经包含了工具层,要用的时候直接调用就好

项目结构说明:

项目结构

  • AggregateService(聚合服务)
  • LocationService(位置服务)
  • MemberService(成员服务)
  • MicroService.Core(核心层 / 基础设施层):只有它是类库,其他服务都是控制台应用程序
  • MicroService.Gateway(网关服务)
  • MicroService.IdentityServer4(认证、授权服务)
  • MicroService.MVCClient(MVC客户端)
  • MicroService.VideoService(视频服务)
  • TeamService(团队服务)

项目依赖

AggregateService 、TeamService、MicroService.VideoService都是依赖MicroService.Core

项目依赖与集群问题

主要区分清楚项目依赖和微服务之间的通讯就好:

  • MicroService.Core是类库,项目依赖是类库依赖,发布时会直接打包了依赖项目的相关文件
  • 微服务之间通讯是通过http或grpc的方式进行服务之间的通讯,相互之间没有依赖

项目依赖的时候,在发布是会自动把依赖的项目打包进来,包括.dll、.exe、.pdb等文件,如下图:

 

AggregateService(聚合服务)结构说明

 

TeamService(团队服务)结构说明 

  • Controllers:控制器层 / 接口层(resful api)
    • 依赖Server层:构造函数注入时依赖,控制器的方法调用服务层server的方法
    • 依赖appsettings文件的ConsulRegistry配置:构造函数时依赖,在Starup类的Configure方法中有注入Consul相关配置
    • 依赖Models层
  • Models:领域模型层
    • 数据库模型:数据库根据它生产对应的表的字段、关系等
    • 视图模型 / 领域模型:提供前端使用到的视图模型 / 领域模型
  • Services:领域服务层(数据交互,包含业务逻辑)
    • 依赖仓储层:构造函数注入时依赖
    • 增、删、改、查方法,方法内只有调用仓储层的方法
    • 为什么要服务层:
      • 重用:把不同服务的调用都在server层中完成
      • 扩展:如果控制器直接调用仓储,有修改时可能会修改很多控制器很麻烦,有服务层把相同功能放在一起,修改也小
  • Repositories:领域仓储层
    • 增、删、改、查的方法,方法内有具体实现,没有业务逻辑
    • 依赖数据库上下文:构造函数注入时依赖
    • 方便更换数据库

 

分布式事务omega

备注:omega文件夹下的4个类库不需要手工创建,下载源码中包含有,在项目中添加一个文件夹然后添加现有项目,然后在微服务层引用

  • Servicecomb.Saga.Omega.Abstractions:抽象层
  • Servicecomb.Saga.Omega.AspNetCore:AspNetCore层
  • Servicecomb.Saga.Omega.Core:核心层
  • Servicecomb.Saga.Omega.Protocol:协议层

测试Test

  • TeamService.Tests:团队服务测试 

 

微服务之间通信

  • 每个服务器启用时用Core层的UseConsulRegistry把自己服务根据服务名、地址注册到consul中
  • 在Core层中的ConsulHttpClient类内已经把HttpClientIHttpClientFactoryHttpResponseMessage
  • 在聚合服务调用其他服务时,根据地址去调用,例如调用团队服务器时是通过HttpTeamServiceClient中团队地址是:https/TeamService//Teams

微服务如何拆分:

架构演进

  • 单体架构
  • 单数据库多应用架构
  • 主从数据库读写分离架构
  • 主从数据库读写分离+缓存架构
  • 消息队列架构
  • 面向服务(SOA)架构
  • 微服务架构

 

dapr

posted @ 2020-04-26 19:34  日积月累码农  阅读(1091)  评论(0编辑  收藏  举报