zoukankan      html  css  js  c++  java
  • 微服务架构:介绍、分布式与集群、架构四要素、设计模式、架构说明、项目结构说明、通讯方式、架构演进

    参考

    书籍:《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

    如有错误,欢迎您指出。
    本文版权归作者和博客园共有,欢迎转载,但必须在文章页面给出原文链接,否则保留追究法律责任的权利。
  • 相关阅读:
    WebService 入门程序(一)
    WinXP系统服务详细列表
    windows下使用openssl的一种方法
    如何搭建Visual Studio的内核编程开发环境
    在CentOS下源码安装 Xen并搭建Windows虚拟机
    微信聊天记录查看器(程序+源码)
    实现了一个简单的key-value存储系统
    TFS二次开发系列:五、工作项查询
    匿名类型是不是强类型?
    近期微博吐槽言论存档,涉及“性能优化”、C++陋习等
  • 原文地址:https://www.cnblogs.com/qingyunye/p/12781780.html
Copyright © 2011-2022 走看看