通过silky框架在.net平台构建微服务应用
必要前提
(必须) 安装 .net5 或是 .net6 sdk。
(必须) 您可以使用visual studio 或是rider作为开发工具。
(必须) 您必须准备一个可用的
zookeeper
服务作为服务注册中心。(必须) 使用选择
redis
服务作为分布式缓存服务。
使用Web主机构建微服务应用
开发者可以通过.net平台提供Web 主机来构建silky微服务应用。
使用webhost来构建的Silky微服务应用,不但可以作为微服务应用的服务提供者(服务内部可以通过SilkyRpc框架进行通信);也提供http服务,http请求通过应用服务方法(服务条目)生成的webapi,通过silky设定的路由规则即可访问微服务应用提供的相关服务。
我们通过如下步骤可以快速的构建一个使用Web 主机构建的Silky微服务应用。
- 新增一个控制台应用或是ASP.NET Core Empty应用
- 安装
Silky.Agent.Host
包
通过 Nuget Package Manger 安装Silky.Agent.Host
包:
或是通过控制台命令安装包:
PM> Install-Package Silky.Agent.Host -Version 3.0.2
- 在
Main
方法中构建silky主机
namespace Silky.Sample
{
using Microsoft.Extensions.Hosting;
using System.Threading.Tasks;
class Program
{
public static async Task Main(string[] args)
{
await CreateHostBuilder(args).Build().RunAsync();
}
private static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.ConfigureSilkyWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>());
}
}
}
- 在启用类中配置服务和置中间件、路由
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Silky.Http.Core;
namespace Silky.Sample
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
// 新增必要的服务
services.AddSilkyHttpCore()
.AddSwaggerDocuments()
.AddRouting();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// 判断是否开发环境
if (env.IsDevelopment())
{
// 开发环境使用开发者异常调式页面
app.UseDeveloperExceptionPage();
// 开发环境使用Swagger在线文档
app.UseSwaggerDocuments();
}
// 使用路由中间件
app.UseRouting();
// 添加其他asp.net core中间件...
// 配置路由
app.UseEndpoints(endpoints =>
{
// 配置SilkyRpc路由
endpoints.MapSilkyRpcServices();
});
}
}
}
- 更新配置
silky支持通过json
或是yml
格式进行配置。您可以通过appsettings.json
为公共配置项指定配置信息,也可以通过新增appsettings.${ENVIRONMENT}.json
文件为指定的环境更新配置属性。
一般地,您必须指定rpc通信的token
,服务注册中心地址等配置项。如果您使用redis作为缓存服务,那么您还需要将distributedCache:redis:isEnabled
配置项设置为true
,并给出redis服务缓存的地址。
在appsettings.json
配置文件中新增如下配置属性:
{
"RegistryCenter": {
"Type": "Zookeeper",
"ConnectionStrings": "127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183;127.0.0.1:2184,127.0.0.1:2185,127.0.0.1:2186"
},
"DistributedCache": {
"Redis": {
"IsEnabled": true,
"Configuration": "127.0.0.1:6379,defaultDatabase=0"
}
},
"Rpc": {
"Token": "ypjdYOzNd4FwENJiEARMLWwK0v7QUHPW",
"Port": 2200
}
}
将配置文件属性的复制到输出目录,设置为: 始终复制 或是 如果较新则复制。
- 创建zookeeper服务和redis缓存服务
在该示例项目中,我们使用Zookeeper
作为服务注册中心。我们在silky的示例项目中给出各种基础服务的docker-compose的编排文件,其中,也包括了zookeeper和redis服务的。
将docker-compose.zookeeper.yml和docker-compose.redis.yml拷贝到本地,保存为相同名称的文件,进入到保存文件的本地目录。
# 创建一个名称为silky_service_net的docker网络
docker network create silky_service_net
# 使用docker-compose创建zookeeper和redis服务
docker-compose -f docker-compose.zookeeper.yml -f docker-compose.redis.yml up -d
- 微服务应用的其他层(项目)
完成主机项目后,您可以新增应用接口层、应用层、领域层、基础设施层等其他项目,更多内容请参考微服务架构节点。
一个典型的微服务模块的划分与传统的DDD
领域模型的应用划分基本一致。需要将应用接口单独的抽象为一个程序集,方便被其他微服务应用引用,其他微服务应用通过应用接口生成RPC代理,与该微服务通信。
一个典型的微服务模块的项目结构如下所示:
项目的依赖关系如下:
(1) 主机项目依赖应用层,从而达到对应用的托管。
(2) 应用接口层用于定义服务接口和DTO
对象,应用层需要依赖应用接口层,实现定义好的服务接口。
(3) 领域层主要用于实现具体的业务逻辑,可以依赖自身的应用接口层以及其他微服务应用的应用接口层(开发者可以通过nuget包安装其他微服务应用的应用接口项目或是直接添加项目的方式进行引用);领域层依赖自身的应用接口层的原因是为了方便使用DTO
对象;引用其他微服务的应用接口层可以通过接口生成的动态代理,与其他微服务通过SilkyRPC
框架进行通信。
(4) 领域共享层(Domain.Shared) 一般用于定义ddd概念中的值类型以及枚举等,方便被其他微服务应用引用。
(5) EntityFramework作为基础服务层,提供数据访问能力,当然,开发者也可以选择使用其他ORM框架。
- 应用接口的定义和实现
应用接口层(Silky.Sample.Application.Contracts) 安装包Silky.Rpc
:
或是通过控制台命令安装包:
PM> Install-Package Silky.Rpc -Version 3.0.2
新增一个服务接口IGreetingAppService
,并且定义一个Say()
方法,应用接口需要使用[ServiceRoute]
特性进行标识。
[ServiceRoute]
public interface IGreetingAppService
{
Task<string> Say(string line);
}
接下来,我们需要 应用层(Silky.Sample.Application) 依赖(引用) 应用接口层(Silky.Sample.Application.Contracts), 并新增一个服务类GreetingAppService
,通过它实现服务接口IGreetingAppService
。
public class GreetingAppService : IGreetingAppService
{
public Task<string> Say(string line)
{
return Task.FromResult($"Hello {line}");
}
}
- 通过Swagger文档在线调试
运行应用程序,即可打开swagger在线文档。开发者可以通过swagger生成的在线文档调试API。
使用.NET通用主机构建微服务应用
开发者可以通过.net平台提供通用主机来构建silky微服务应用。
使用.NET 通用主机构建微服务应用只能作为服务提供者,通过SilkyRPC框架与其他微服务应用进行通信;无法提供http服务,也就是说,集群外部无法直接访问该微服务应用,只能通过网关或是其他提供http服务的微服务应用访问该微服务应用的服务。
使用.NET 通用主机构建Silky微服务应用的步骤与使用使用Web 主机构建微服务应用的步骤基本一致,区别在于无需配置Startup
类,也不能配置http中间件(配置了也无效);开发者可以通过实现IConfigureService
接口来完成对服务注入的配置。
1-2 步骤与使用web主机构建微服务应用一致。
- 在
Main
方法中构建silky主机
namespace Silky.Sample
{
using Microsoft.Extensions.Hosting;
using System.Threading.Tasks;
class Program
{
public static async Task Main(string[] args)
{
await CreateHostBuilder(args).Build().RunAsync();
}
private static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.ConfigureSilkyGeneralHostDefaults();
}
}
}
创建ConfigureService
类,用于实现IConfigureService
接口,在ConfigureServices()
方法中配置服务注入依赖。
public class ConfigureService : IConfigureService
{
public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
services.AddSilkySkyApm()
//其他服务(包括第三方组件的服务或是silky框架的其他服务,例如:Efcore组件,MessagePack编解码,Cap或是MassTransit等分布式事件总线等)
//...
;
}
}
5-7步骤与使用web主机构建微服务应用一致。
启动应用后,我们可以在控制台看到相关的日志输出,应用服务启动成功。
用户无法直接访问该微服务应用,必须通过网关引用该微服务的 应用接口层 ,通过网关的提供的http服务间接的访问该微服务应用提供的服务。
构建具有websocket服务能力的微服务应用
开发者通过构建具有websocket服务能力的微服务应用, 这样的微服务应用可以除了可以作为服务提供者之外,还具有提供websocket通信的能力(websocket端口默认为:3000)。可以通过与服务端进行握手会话(可以通过网关代理),服务端实现向客户单推送消息的能力。
构建具有websocket服务能力的微服务应用与使用.NET通用主机构建微服务应用的步骤一致,只是用于构建微服务应用的方法有差异。
1-2 步骤与使用web主机构建微服务应用一致。
- 在
Main
方法中构建silky主机
namespace Silky.Sample
{
using Microsoft.Extensions.Hosting;
using System.Threading.Tasks;
class Program
{
public static async Task Main(string[] args)
{
await CreateHostBuilder(args).Build().RunAsync();
}
private static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureSilkyWebSocketDefaults();
}
}
创建ConfigureService
类,用于实现IConfigureService
接口,在ConfigureServices()
方法中配置服务注入依赖。
public class ConfigureService : IConfigureService
{
public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
services.AddSilkySkyApm()
//其他服务(包括第三方组件的服务或是silky框架的其他服务,例如:Efcore组件,MessagePack编解码,Cap或是MassTransit等分布式事件总线等)
//...
;
}
}
5-6步骤与使用web主机构建微服务应用一致。
- 构建具有提供websocket服务能力的服务
应用服务接口的定义与一般应用服务的接口定义一样,只需要在一个普通的接口标识[ServiceRoute]
特性即可。
[ServiceRoute]
public interface ITestAppService
{
// 可以定义其他方法(服务条目),定义的方法可以与其他微服务应用通过RPC框架进行通信
}
我们需要在 应用层(Silky.Sample.Application) 安装 Silky.WebSocket
包。
PM> Install-Package Silky.WebSocket -Version 3.0.2
并新增一个 TestAppService
类, 通过它来实现 ITestAppService
, 除此之外,我们需要 TestAppService
类继承 WsAppServiceBase
基类。
public class TestAppService : WsAppServiceBase, ITestAppService
{
private readonly ILogger<TestAppService> _logger;
public TestAppService(ILogger<TestAppService> logger)
{
_logger = logger;
}
// 当建立websocket会话时
protected override void OnOpen()
{
base.OnOpen();
_logger.LogInformation("websocket established a session");
}
// 当服务端接收到客服端的消息时
protected override void OnMessage(MessageEventArgs e)
{
_logger.LogInformation(e.Data);
}
// 当websocket会话关闭时
protected override void OnClose(CloseEventArgs e)
{
base.OnClose(e);
_logger.LogInformation("websocket disconnected");
}
// 其他服务方法
}
启动应用后,我们可以在控制台看到相关的日志输出,应用服务启动成功。我们定义的websocket的服务的webapi地址为:/api/test
。
- 客户端透过网关与websocket服务握手
客户端无法直接与该微服务应用进行握手,必须通过网关引用该微服务的 应用接口层 ,通过网关的提供的websocket代理服务与该微服务进行握手,通过ws[s]://gateway_ip[:gateway_port]/websocket_webapi
与之前定义websocket服务进行会话。
我们在构建的网关应用中引用该微服务的应用接口层,并启动网关应用(网关服务地址为127.0.0.1:5000
),并可通过地址:ws://127.0.0.1:5000/api/test
与之前定义的websocket服务进行握手和通信。
客户端与websocket服务进行握手时,需要通过qstring参数
或是请求头设置hashkey
,确保每次通信的微服务应用都是同一个实例。
构建Silky微服务网关
实际上,通过.net平台提供Web主机来构建silky微服务应用,也可以认为是一个网关。我们在这里专门构建的网关与通过.net平台提供Web 主机的区别在于该类型的微服务应用只能作为服务消费者,不能作为服务提供者,不能作为RPC服务提供者。
总的来说,网关是对微服务应用集群来说是一个对接外部的流量入口。
构建过程与通过.net平台提供Web 主机一致,我们只需要将创建主机的方法修改为:
private static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureSilkyGatewayDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
网关项目通过引用其他微服务应用的应用接口层,就可以作为服务消费者通过SilkyRPC框架调用其他微服务应用提供的服务,并且通过网关提供的http相关中间件可以实现生成在线swagger文档,实现统一的api鉴权,http限流,生成dashboard管理端,实现对微服务集群服务提供者实例的健康检查等功能。
开源地址
- github: https://github.com/liuhll/silky
- gitee: https://gitee.com/liuhll2/silky
在线文档
在线示例
通过silky框架在.net平台构建微服务应用的更多相关文章
- 使用silky脚手架构建微服务应用
目录 模板简介 构建独立应用的模板Silky.App.Template 构建模块化应用的模板Silky.Module.Template 开源地址 在线文档 模板简介 使用 dotnet new 命令可 ...
- Cola Cloud 基于 Spring Boot, Spring Cloud 构建微服务架构企业级开发平台
Cola Cloud 基于 Spring Boot, Spring Cloud 构建微服务架构企业级开发平台: https://gitee.com/leecho/cola-cloud
- 如何使用 Java 构建微服务?
[编者按]微服务背后的大理念是将大型.复杂且历时长久的应用在架构上设计为内聚的服务,这些服务能够随着时间的流逝而演化.本文主要介绍了利用 Java 生态系统构建微服务的多种方法,并分析了每种方法的利弊 ...
- 基于Spring Cloud和Netflix OSS构建微服务,Part 2
在上一篇文章中,我们已使用Spring Cloud和Netflix OSS中的核心组件,如Eureka.Ribbon和Zuul,部分实现了操作模型(operations model),允许单独部署的微 ...
- Chris Richardson微服务翻译:构建微服务之使用API网关
Chris Richardson 微服务系列翻译全7篇链接: 微服务介绍 构建微服务之使用API网关(本文) 构建微服务之微服务架构的进程通讯 微服务架构中的服务发现 微服务之事件驱动的数据管理 微服 ...
- 手把手教你用Spring Cloud和Docker构建微服务
什么是Spring Cloud? Spring Cloud 是Pivotal提供的用于简化分布式系统构建的工具集.Spring Cloud引入了云平台连接器(Cloud Connector)和服务连接 ...
- 微服务系列(二):使用 API 网关构建微服务
编者的话|本文来自 Nginx 官方博客,是微服务系列文章的第二篇,本文将探讨:微服务架构是如何影响客户端到服务端的通信,并提出一种使用 API 网关的方法. 作者介绍:Chris Richardso ...
- 0102-使用 API 网关构建微服务
一.移动客户端如何访问这些服务 1.1.客户端与微服务直接通信[很少使用] 从理论上讲,客户端可以直接向每个微服务发送请求.每个微服务都有一个公开的端点(https ://.api.company.n ...
- 技术分享:Dapr,让开发人员更轻松地构建微服务应用
最近一直在学习微服务相关的技术.微服务架构已成为构建云原生应用程序的标准,并且可以预见,到2022年,将有90%的新应用程序采用微服务架构.微服务架构提供了令人信服的好处,包括可伸缩性,松散的服务耦合 ...
随机推荐
- PHP操作用户提交内容时需要注意的危险函数
对于我们的程序开发来说,用户的输入是解决安全性问题的第一大入口.为什么这么说呢?不管是SQL注入.XSS还是文件上传漏洞,全部都和用户提交的输入参数有关.今天我们不讲这些问题,我们主要探讨下面对用户的 ...
- Java面向对象系列(8)- Super详解
场景一 场景二 场景三 场景四 注意:调用父类的构造器,super()必须在子类构造器的第一行 场景五 场景六 super注意点 super调用父类得构造方法(即构造器),必须在构造方法得第一个 su ...
- 网络IO模型与Reactor模式
一.三种网络IO模型: 分类: BIO 同步的.阻塞式 IO NIO 同步的.非阻塞式 IO AIO 异步非阻塞式 IO 阻塞和同步的概念: 阻塞:若读写未完成,调用读写的线程一直等待 非阻塞:若读写 ...
- python并发与futures模块
非并发程序(用于对比) 从网上下载20个国家的国旗图像: import os import time import sys import requests # 导入requests库 POP20_CC ...
- Jemter请求乱码解决方案
1:jemeter查看结果树乱码 (1)在jmeter的bin目录下找到jmeter.properties这个文件,添加上 sampleresult.default.encoding=utf-8 (2 ...
- YbtOJ#643-机器决斗【贪心,李超树】
正题 题目链接:https://www.ybtoj.com.cn/problem/643 题目大意 \(n\)个机器人,第\(i\)个攻击力为\(A_i\),防御为\(D_i\). 然后你每次可以对一 ...
- CSharp委托与匿名函数
CSharp委托与匿名函数 场景 面对事件处理,我们通常会通过定义某一个通用接口,在该接口中定义方法,然后在框架代码中,调用实现该接口的类实例的方法来实现函数的回调.可能这样来说有些抽象,那我们提供一 ...
- nginx配置禁止爬虫配置
1.在配置文件里添加禁止爬虫配置 server { ------ #添加如下内容即可防止爬虫 if ($http_user_agent ~* "qihoobot|Baiduspider|Go ...
- Python小知识之对象的比较
好久不见 国庆回了趟老家,躺平了10天.作息时间基本和小学生差不多,8.9点就睡了, 那滋味别提多舒服了.时间也和小时候过得一样慢了...长时间不更新,还是不行滴,粉都快掉没了. 今天就结合日常生活的 ...
- react之组件生命周期
四个阶段 初始化 运行中 销毁 错误处理(16.3以后) 初始化 constructor static getDerivedStateFromProps() componentWillMount() ...