通过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%的新应用程序采用微服务架构.微服务架构提供了令人信服的好处,包括可伸缩性,松散的服务耦合 ...
随机推荐
- leetcode8 字符串转换为整数
最笨的办法实现 一步步判断 /** * @param {string} s * @return {number} */ var myAtoi = function(s) { s = s.trim() ...
- Mixed Content: The page at 'xxx' was loaded over HTTPS, but requested an insecure resource 'xxx'.
HTTPS页面里动态的引入HTTP资源,比如引入一个js文件,会被直接block掉的.在HTTPS页面里通过AJAX的方式请求HTTP资源,也会被直接block掉的. Mixed Content: T ...
- (原创)一步步优化业务代码之——从数据库获取DataTable并绑定到List<Class>
一,前言 现实业务当中,有一个很常见的流程:从数据库获取数据到DataTable,然后将DataTable绑定到实体类集合上,一般是List<Class>,代码写起来也简单:遍历+赋值就可 ...
- JavaScript进阶面向对象ES6
类和对象 对象:万物皆对象,对象是一个具体的事物,看得见摸得着的实物 对象是由属性和方法组成的: 属性:事物的特征,再对象中用属性来表示(常用名词) 方法:事物的行为,再对象中用方法来表示(常用动词) ...
- javascript 求最大前5个数; 对象 深拷贝 deep copy
* 用数组 function getTopN(a, n) { function _cloneArray(aa) { var n = aa.length, a = new Array(n); for ( ...
- mybatis关系表
<select id="selectSingleQuestion" resultType="remarkPaper"> select FrontTi ...
- setTimeout 与setInterval的区别
setTimeout(code,millisec) 方法用于在指定的毫秒数后调用函数或计算表达式 setInterval(code,millisec) 方法可按照指定的周期(以毫秒计)来调用函数或计算 ...
- 鸿蒙内核源码分析(文件句柄篇) | 深挖应用操作文件的细节 | 百篇博客分析OpenHarmony源码 | v69.01
百篇博客系列篇.本篇为: v69.xx 鸿蒙内核源码分析(文件句柄篇) | 深挖应用操作文件的细节 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说 ...
- Python编码规范(养成好的编码习惯很重要)
学习过程养成良好的编码习惯 1. 类名采用驼峰命名法,即类名的每个首字母都大写,如:class HelloWord,类名不使用下划线 2. 函数名只使用小写字母和下划线 3.定义类后面包含一个文档字符 ...
- Kubernetes-Service介绍(一)-基本概念
前言 本篇是Kubernetes第八篇,大家一定要把环境搭建起来,看是解决不了问题的,必须实战.Pod篇暂时应该还缺少两篇,等Service和存储相关内容介绍以后,补充剩下的两篇,有状态的Pod会涉及 ...