【NET CORE微服务一条龙应用】第一章 网关使用与配置
简介
微服务的系统应用中,网关系统使用的是ocelot,ocelot目前已经比较成熟了
ocelot就不做介绍了,等整体介绍完后再进行各类扩展介绍,ocelot源码地址:https://github.com/ThreeMammals/Ocelot
ocelot目前由很多功能组件组成,每个组件都可以根据自己的实际情况进行扩展(暂时不做过多介绍)
本文主要介绍ocelot网关使用中个人认为应该最先处理的东西
健康检查
在实际的应用中网关项目都会部署多台,然后通过nginx进行软负载,在更新部署网关项目的过程中服务肯定是无法使用,这个时候我们就需要利用nginx的健康检查机制进行控制
网关需要给nginx提供一个健康检查地址,ocelot使用的url path地址进行路由匹配,当匹配不到时会返回404,所以我们需要单独处理一个健康检查地址
Ocelot提供了一个中间件配置替换的方法OcelotPipelineConfiguration,我们对OcelotPipelineConfiguration的PreErrorResponderMiddleware中间件方法进行扩展,代码如下:
var conf = new OcelotPipelineConfiguration()
{
PreErrorResponderMiddleware = async (ctx, next) =>
{
if (ctx.HttpContext.Request.Path.Equals(new PathString("/")))
{
await ctx.HttpContext.Response.WriteAsync("ok");
}
else
{
await next.Invoke();
}
}
};
app.UseOcelot(conf).Wait();
网关和路由配置
网关的配置包含四个部分,ReRoutes、DynamicReRoutes、Aggregates、GlobalConfiguration,
ocelot配置的获取默认是使用配置文件的方式,上面已经说了网关一般都会部署多台,使用文件配置还是存在一定弊端
ocelot的配置获取方法是IFileConfigurationRepository接口,所以如果我们实现了此接口就可以满足配置存储方式的扩展,目前已扩展mysql和redis,代码如下
redis:
public class RedisFileConfigurationRepository: IFileConfigurationRepository
{
private readonly RedisClient _redisClient;
private readonly string _apiGatewayKey;
private readonly string _redisConnection; public RedisFileConfigurationRepository(RedisClient redisClient, string apiGatewayKey, string redisConnection)
{
_redisClient = redisClient;
_apiGatewayKey = apiGatewayKey;
_redisConnection = redisConnection;
} public async Task<Response<FileConfiguration>> Get()
{
var redis = _redisClient.GetDatabase(_redisConnection, ); var json = await redis.StringGetAsync($"ApiGatewayConfig:{_apiGatewayKey}"); if(json.IsNullOrEmpty)
return new OkResponse<FileConfiguration>(new FileConfiguration { }); var fileConfig = JsonConvert.DeserializeObject<FileConfiguration>(json); return new OkResponse<FileConfiguration>(fileConfig);
} public async Task<Response> Set(FileConfiguration fileConfiguration)
{
return await Task.FromResult(new OkResponse());
}
}
mysql:
public class MySqlFileConfigurationRepository : IFileConfigurationRepository
{
private readonly IDbRepository<ConfigurationInfo> _configDbRepository;
private readonly IDbRepository<ReRouteInfo> _routeDbRepository;
private readonly string _apiGatewayKey; public MySqlFileConfigurationRepository(IDbRepository<ConfigurationInfo> configDbRepository, IDbRepository<ReRouteInfo> routeDbRepository, string apiGatewayKey)
{
_configDbRepository = configDbRepository;
_routeDbRepository = routeDbRepository;
_apiGatewayKey = apiGatewayKey;
} public async Task<Response<FileConfiguration>> Get()
{
var st = DateTime.Now;
var fileConfig = new FileConfiguration();
var configInfo = await _configDbRepository.GetFirstAsync(it => it.GatewayKey == _apiGatewayKey);
if (configInfo != null)
{
// config
var fgc = new FileGlobalConfiguration
{
BaseUrl = configInfo.BaseUrl,
DownstreamScheme = configInfo.DownstreamScheme,
RequestIdKey = configInfo.RequestIdKey,
};
if (!string.IsNullOrWhiteSpace(configInfo.HttpHandlerOptions))
fgc.HttpHandlerOptions = ToObject<FileHttpHandlerOptions>(configInfo.HttpHandlerOptions);
if (!string.IsNullOrWhiteSpace(configInfo.LoadBalancerOptions))
fgc.LoadBalancerOptions = ToObject<FileLoadBalancerOptions>(configInfo.LoadBalancerOptions);
if (!string.IsNullOrWhiteSpace(configInfo.QoSOptions))
fgc.QoSOptions = ToObject<FileQoSOptions>(configInfo.QoSOptions);
if (!string.IsNullOrWhiteSpace(configInfo.RateLimitOptions))
fgc.RateLimitOptions = ToObject<FileRateLimitOptions>(configInfo.RateLimitOptions);
if (!string.IsNullOrWhiteSpace(configInfo.ServiceDiscoveryProvider))
fgc.ServiceDiscoveryProvider = ToObject<FileServiceDiscoveryProvider>(configInfo.ServiceDiscoveryProvider);
fileConfig.GlobalConfiguration = fgc; // reroutes
var reRouteResult = await _routeDbRepository.GetListAsync(it => it.GatewayId == configInfo.GatewayId && it.State == );
if (reRouteResult.Count > )
{
var reroutelist = new List<FileReRoute>();
foreach (var model in reRouteResult)
{
var m = new FileReRoute()
{
UpstreamHost = model.UpstreamHost,
UpstreamPathTemplate = model.UpstreamPathTemplate, DownstreamPathTemplate = model.DownstreamPathTemplate,
DownstreamScheme = model.DownstreamScheme, ServiceName = model.ServiceName,
Priority = model.Priority,
RequestIdKey = model.RequestIdKey,
Key = model.Key,
Timeout = model.Timeout,
};
if (!string.IsNullOrWhiteSpace(model.UpstreamHttpMethod))
m.UpstreamHttpMethod = ToObject<List<string>>(model.UpstreamHttpMethod);
if (!string.IsNullOrWhiteSpace(model.DownstreamHostAndPorts))
m.DownstreamHostAndPorts = ToObject<List<FileHostAndPort>>(model.DownstreamHostAndPorts);
if (!string.IsNullOrWhiteSpace(model.SecurityOptions))
m.SecurityOptions = ToObject<FileSecurityOptions>(model.SecurityOptions);
if (!string.IsNullOrWhiteSpace(model.CacheOptions))
m.FileCacheOptions = ToObject<FileCacheOptions>(model.CacheOptions);
if (!string.IsNullOrWhiteSpace(model.HttpHandlerOptions))
m.HttpHandlerOptions = ToObject<FileHttpHandlerOptions>(model.HttpHandlerOptions);
if (!string.IsNullOrWhiteSpace(model.AuthenticationOptions))
m.AuthenticationOptions = ToObject<FileAuthenticationOptions>(model.AuthenticationOptions);
if (!string.IsNullOrWhiteSpace(model.RateLimitOptions))
m.RateLimitOptions = ToObject<FileRateLimitRule>(model.RateLimitOptions);
if (!string.IsNullOrWhiteSpace(model.LoadBalancerOptions))
m.LoadBalancerOptions = ToObject<FileLoadBalancerOptions>(model.LoadBalancerOptions);
if (!string.IsNullOrWhiteSpace(model.QoSOptions))
m.QoSOptions = ToObject<FileQoSOptions>(model.QoSOptions);
if (!string.IsNullOrWhiteSpace(model.DelegatingHandlers))
m.DelegatingHandlers = ToObject<List<string>>(model.DelegatingHandlers);
reroutelist.Add(m);
}
fileConfig.ReRoutes = reroutelist;
}
}
Console.WriteLine((DateTime.Now - st).TotalMilliseconds);
return new OkResponse<FileConfiguration>(fileConfig);
} public async Task<Response> Set(FileConfiguration fileConfiguration)
{
return await Task.FromResult(new OkResponse());
} /// <summary>
/// 将Json字符串转换为对象
/// </summary>
/// <param name="json">Json字符串</param>
private T ToObject<T>(string json)
{
if (string.IsNullOrWhiteSpace(json))
return default(T);
return JsonConvert.DeserializeObject<T>(json);
}
}
可以看到四项配置里并不是全部都进行可配置化,如果有需求可以自行增加字段实现
redis的存储是大json方式,而mysql是一条一条的,因为配置的管理是以mysql为主,然后同步到其他存储介质中的
网关配置的更新
有加载就有更新,在ocelot中配置的更新是使用自己的实现来完成配置的热更新,方式如下
1、配置文件方式是通过配置文件的IOptionsMonitor的OnChange方式重新加载配置信息
2、第三方存储方式是通过默认实现的FileConfigurationPoller方法定时(默认1s)取获取配置信息的
所以我们扩展的获取配置形式,在注册的时候要把FileConfigurationPoller HostedService一同注入进去,代码如下
public static IOcelotBuilder AddConfigStoredInRedis(this IOcelotBuilder builder, string apiGatewayKey, string redisConnectionString)
{
builder.Services.AddSingleton<RedisClient>();
builder.Services.AddHostedService<FileConfigurationPoller>();
builder.Services.AddSingleton<IFileConfigurationRepository>(sp =>
{
return new RedisFileConfigurationRepository(sp.GetRequiredService<RedisClient>(), apiGatewayKey, redisConnectionString);
});
return builder;
}
其中涉及到Bucket.DbContext和Bucket.Redis组件很简单,也可自行实现
配置的管理
其实最开始的时候,使用的是consul存储配置,然后通过网关自带的配置接口进行配置的管理,但是在ocelot的一次升级的时候出现了一个问题(配置信息丢失),虽然当时修改了ocelot的源码解决了,后来还是决定扩展存储方式,所以上面的获取配置接口的set方法都不实现了
上面已经说了是已mysql进行配置存储然后同步到其他介质上,所以我们只要维护好mysql数据库就可以了
具体代码就不贴了,后续会进行具体介绍,管理项目地址:github地址,截几张管理图



【NET CORE微服务一条龙应用】第一章 网关使用与配置的更多相关文章
- 【NET CORE微服务一条龙应用】第三章 认证授权与动态权限配置
介绍 系列目录:[NET CORE微服务一条龙应用]开始篇与目录 在微服务的应用中,统一的认证授权是必不可少的组件,本文将介绍微服务中网关和子服务如何使用统一的权限认证 主要介绍内容为: 1.子服务如 ...
- 【NET CORE微服务一条龙应用】第二章 配置中心使用
背景 系列目录:[NET CORE微服务一条龙应用]开始篇与目录 在分布式或者微服务系统里,通过配置文件来管理配置内容,是一件比较令人痛苦的事情,再谨慎也有湿鞋的时候,这就是在项目架构发展的过程中,配 ...
- 【NET CORE微服务一条龙应用】应用部署
简介 系列目录:[NET CORE微服务一条龙应用]开始篇与目录 本章主要介绍https://github.com/q315523275/FamilyBucket上微服务一条龙应用,在实际使用中的应用 ...
- 【NET CORE微服务一条龙应用】开始篇与目录
简介 随着业务的发展和变更,项目原先的分布式框架应用业务发展已有些不适应,所以18年初开始准备使用微服务框架,当时正好看到了ocelot项目,特意翻看了源码,发现很灵活和易扩展 于是就开始了微服务的开 ...
- .NET Core微服务二:Ocelot API网关
.NET Core微服务一:Consul服务中心 .NET Core微服务二:Ocelot API网关 .NET Core微服务三:polly熔断与降级 本文的项目代码,在文章结尾处可以下载. 本文使 ...
- 基于.NET CORE微服务框架 -谈谈surging API网关
1.前言 对于最近surging更新的API 网关大家也有所关注,也收到了不少反馈提出是否能介绍下Api网关,那么我们将在此篇文章中剥析下surging的Api 网关 开源地址:https://git ...
- .NET Core微服务一:Consul服务中心
本文的项目代码,在文章结尾处可以下载. 防爬虫,本文的网址是:https://www.cnblogs.com/shousiji/p/12253295.html 本文使用的环境:Windows10 64 ...
- .Net微服务实践(四)[网关]:Ocelot限流熔断、缓存以及负载均衡
目录 限流 熔断 缓存 Header转化 HTTP方法转换 负载均衡 注入/重写中间件 后台管理 最后 在上篇.Net微服务实践(三)[网关]:Ocelot配置路由和请求聚合中我们介绍了Ocelot的 ...
- 基于.NET CORE微服务框架 -surging的介绍和简单示例 (开源)
一.前言 至今为止编程开发已经11个年头,从 VB6.0,ASP时代到ASP.NET再到MVC, 从中见证了.NET技术发展,从无畏无知的懵懂少年,到现在的中年大叔,从中的酸甜苦辣也只有本人自知.随着 ...
随机推荐
- SPOJ - AMR11B
题目链接:https://www.spoj.com/problems/AMR11B/en/ 题目大意就是要你求图形覆盖的格点数,标记每个图形里的未标记格点(包括边界),总标记数就是覆盖的总格点数. # ...
- 别人的Linux私房菜(11)认识与学习BASH
Linux下使用BASH Bourne Again Shell 另外一种由用于Unix的伯克利大学的Bill Joy设计的C Shell 系统中合法的shell会写入到/etc/sh ...
- python抢火车票 短信通知
# -*- coding: utf-8 -*- from splinter.browser import Browser from time import sleep import traceback ...
- centos7.2 下 nginx 开机启动
1.在系统服务目录里创建nginx.service文件 1 vi /lib/systemd/system/nginx.service 内容如下 1 2 3 4 5 6 7 8 9 10 11 12 1 ...
- EF6 学习笔记(二):操练 CRUD 增删改查
EF6学习笔记总目录 ASP.NET MVC5 及 EF6 学习笔记 - (目录整理) 接上篇: EF6 学习笔记(一):Code First 方式生成数据库及初始化数据库实际操作 本篇原文链接: I ...
- Linux基础理论
本节内容 1. Linux的安装及相关配置 2. UNIX和Linux操作系统概述 3. Linux命令及帮助 4. 目录结构 6. 用户.群组和权限 7. 用户.群组和权限的深入讨论 1 ...
- 使用gulp+bebal实现前端自动化es6转es5的构建
说明:es6语法已经越来越普及,但是一些低版本的浏览器不支持es6的语法特性,所以我们在开发完前端项目后,往往需要统一把前端es6的代码编译成es5的代码.本文介绍的就是如何手动和自动的把es6转成e ...
- Javascript多线程
最近项目中要用一个倒计时,但是当弹窗的时候倒计时会被阻塞,所以我想到使用Javascript多线程解决该问题. 虽然JavaScript是单线程的,但是通过worker可以让Javascript另外开 ...
- Android精通教程-第一节Android入门简介
前言 大家好,给大家带来Android精通教程-第一节Android入门简介的概述,希望你们喜欢 每日一句 If life were predictable it would cease to be ...
- shell 中的三种引号的作用
1. 单引号(' ') 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的: 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用. 2. 双 ...