介绍

微服务中有关键的几项技术,其中网关和服务服务发现,服务注册相辅相成。

首先解释几个本次教程中需要的术语

网关 Gateway(API GW / API 网关),顾名思义,是企业 IT 在系统边界上提供给外部访问内部接口服务的统一入口,简化了外部由于多服务协同完成任务时的繁琐配置。网关组件有Kong,ocelot,

服务发现:通过网关访问内部各个微服务,网关要找到所需服务的过程称为服务发现

服务注册:既然有服务发现,前提是要把所需服务提前“录入”,这个录入的过程称为服务注册。服务注册可配置文件(人肉方式不推荐),也可用服务注册组件如Consul或者Eureka等等(推荐)

搭建Consul集群(Windows)

官网下载Consul程序,https://www.consul.io/downloads.html

下载下来就是一个可执行文件Consul.exe

Consul有两种代理模式,一种server,一种client,官方建议Server端达到3台以上才可高可用,但不要太多,太多会给集群间数据同步造成压力,client数量不限。

多个server端之间会选择出一个leader,当一个server的leader宕机则会从其他server端”投票“选择新的leader

实践

这里server我们用2台实验

192.168.74.55

192.168.74.54

1台Client

192.168.74.161

consul启动有两种方式一种是命令行,一种是配置文件的方式。

命令行方式启动一个consul的server端

consul agent -server -ui -bootstrap-expect 2 -data-dir opt/consul/data -node ServerMaster -bind 192.168.74.55 -client 192.168.74.55
关键参数说明
-server:server模式启动
-ui :开启ui界面(consul.exe内部带了GUI图形界面操作)
 -bootstrap-expect 2:server端到2个时集群生效
-data-dir:consul产生的文件路径(consul自己会产生一下数据存储的位置)
-node:此节点名称
-bind:集群内部通信地址,默认0.0.0.0
-client:此节点绑定的通讯地址
以上只是关键参数,以下是完整参数说明: 
 
 

但是命令启动很繁琐,所以推荐下面的配置文件的方式启动

在consul同文件夹下建立一个server.json的配置文件

{
"datacenter": "dc1",
"data_dir": "opt/consul/data",
"node_name": "consul-server01",
"server": true,
"bootstrap_expect": 2,
"bind_addr": "192.168.74.55",
"client_addr": "192.168.74.55",
"ui":true
}

为了快速启动,再建立一个bat批处理文件runconsul.bat

consul agent -config-dir server.json
pause

双击runconsul.bat启动consul

在192.168.74.54服务器开启一个server端继续以上操作。

命令方式启动

consul agent -server -ui -data-dir opt/consul/data -node Server01 -bind 192.168.74.54 -client 192.168.74.54 -join=192.168.74.55

-join将192.168.74.54加入到192.168.74.55服务器

配置文件方式:

{
"datacenter": "dc1",
"data_dir": "opt/consul/data",
"node_name": "consul-server2",
"server": true,
"bind_addr": "192.168.74.54",
"client_addr": "192.168.74.54",
"ui":true,
"retry_join": ["192.168.74.55"],
"retry_interval": "30s",
"rejoin_after_leave": true,
"start_join":["192.168.74.55"]
}

在192.168.74.161服务器开启一个consul的client端

命令方式:

consul agent -ui -data-dir opt/consul/data -node ServerSlave  -bind 192.168.74.161 -client 192.168.74.161 -join 192.168.74.55

配置文件方式:

{
"datacenter": "dc1",
"data_dir": "opt/consul/data",
"node_name": "consul-client01",
"server": false,
"bind_addr": "192.168.74.161",
"client_addr": "192.168.74.161",
"ui":true,
"retry_join": ["192.168.74.55"],
"retry_interval": "30s",
"rejoin_after_leave": true,
"start_join":["192.168.74.55"]
}

效果

简单Consul集群到这里就搭建成功,只要访问三台服务器任意一个都可数据同步,演示:

netcore集成Consul服务注册

首先新建一个ConsulClient的类库

ConsulRegister.csproj所需组件如下:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Consul" Version="0.7.2.6" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.1.0" />
</ItemGroup> </Project>
 服务发现自动注册,无需手动绑定本机地址,会自动扫描本地ipv4地址和localhost地址,项目中无需再手动创建健康检查接口
ServiceDiscoveryOptions.cs

using System;
using System.Collections.Generic;
using System.Text; namespace ConsulRegister
{
/// <summary>
/// 服务治理第三方组件Consul相关配置参数
/// </summary>
public class ServiceDiscoveryOptions
{
public string ServiceName { get; set; } public ConsulOptions Consul { get; set; }
} public class ConsulOptions
{
public string HttpEndPoint { get; set; }
}
}
RegisterToConsulExtension.cs

using Consul;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets; namespace ConsulRegister
{
public static class RegisterToConsulExtension
{
/// <summary>
/// Add Consul
/// 添加consul
/// </summary>
/// <param name="services"></param>
/// <param name="configuration"></param>
/// <returns></returns>
public static IServiceCollection AddConsul(this IServiceCollection services, IConfiguration configuration)
{
// configuration Consul register address
//配置consul注册地址
services.Configure<ServiceDiscoveryOptions>(configuration.GetSection("ServiceDiscovery")); //configuration Consul client
//配置consul客户端
services.AddSingleton<IConsulClient>(sp => new Consul.ConsulClient(config =>
{
var consulOptions = sp.GetRequiredService<IOptions<ServiceDiscoveryOptions>>().Value;
if (!string.IsNullOrWhiteSpace(consulOptions.Consul.HttpEndPoint))
{
config.Address = new Uri(consulOptions.Consul.HttpEndPoint);
}
})); return services;
} /// <summary>
/// use Consul
/// 使用consul
/// The default health check interface format is http://host:port/HealthCheck
/// 默认的健康检查接口格式是 http://host:port/HealthCheck
/// </summary>
/// <param name="app"></param>
/// <returns></returns>
public static IApplicationBuilder UseConsul(this IApplicationBuilder app)
{
IConsulClient consul = app.ApplicationServices.GetRequiredService<IConsulClient>();
IApplicationLifetime appLife = app.ApplicationServices.GetRequiredService<IApplicationLifetime>();
IOptions<ServiceDiscoveryOptions> serviceOptions = app.ApplicationServices.GetRequiredService<IOptions<ServiceDiscoveryOptions>>();
var features = app.Properties["server.Features"] as FeatureCollection; var port = new Uri(features.Get<IServerAddressesFeature>()
.Addresses
.FirstOrDefault()).Port;
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine($"application port is :{port}");
var addressIpv4Hosts = NetworkInterface.GetAllNetworkInterfaces()
.OrderByDescending(c => c.Speed)
.Where(c => c.NetworkInterfaceType != NetworkInterfaceType.Loopback && c.OperationalStatus == OperationalStatus.Up); foreach (var item in addressIpv4Hosts)
{
var props = item.GetIPProperties();
//this is ip for ipv4
//这是ipv4的ip地址
var firstIpV4Address = props.UnicastAddresses
.Where(c => c.Address.AddressFamily == AddressFamily.InterNetwork)
.Select(c => c.Address)
.FirstOrDefault().ToString();
var serviceId = $"{serviceOptions.Value.ServiceName}_{firstIpV4Address}:{port}"; var httpCheck = new AgentServiceCheck()
{
DeregisterCriticalServiceAfter = TimeSpan.FromMinutes(),
Interval = TimeSpan.FromSeconds(),
//this is default health check interface
//这个是默认健康检查接口
HTTP = $"{Uri.UriSchemeHttp}://{firstIpV4Address}:{port}/HealthCheck",
}; var registration = new AgentServiceRegistration()
{
Checks = new[] { httpCheck },
Address = firstIpV4Address.ToString(),
ID = serviceId,
Name = serviceOptions.Value.ServiceName,
Port = port
}; consul.Agent.ServiceRegister(registration).GetAwaiter().GetResult(); //send consul request after service stop
//当服务停止后想consul发送的请求
appLife.ApplicationStopping.Register(() =>
{
consul.Agent.ServiceDeregister(serviceId).GetAwaiter().GetResult();
}); Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine($"health check service:{httpCheck.HTTP}");
} //register localhost address
//注册本地地址
var localhostregistration = new AgentServiceRegistration()
{
Checks = new[] { new AgentServiceCheck()
{
DeregisterCriticalServiceAfter = TimeSpan.FromMinutes(),
Interval = TimeSpan.FromSeconds(),
HTTP = $"{Uri.UriSchemeHttp}://localhost:{port}/HealthCheck",
} },
Address = "localhost",
ID = $"{serviceOptions.Value.ServiceName}_localhost:{port}",
Name = serviceOptions.Value.ServiceName,
Port = port
}; consul.Agent.ServiceRegister(localhostregistration).GetAwaiter().GetResult(); //send consul request after service stop
//当服务停止后想consul发送的请求
appLife.ApplicationStopping.Register(() =>
{
consul.Agent.ServiceDeregister(localhostregistration.ID).GetAwaiter().GetResult();
}); app.Map("/HealthCheck", s =>
{
s.Run(async context =>
{
await context.Response.WriteAsync("ok");
});
});
return app;
}
}
}

再新建一个.netcore的webapi项目WebA,并且引用ConsulRegister项目

在WebA项目中的Startup.cs文件中加入Consul服务

 public void ConfigureServices(IServiceCollection services)
{
services.AddConsul(Configuration);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} app.UseConsul();
app.UseMvc();
}

在WebA项目的appsettings.json配置文件中加入以下Consul服务端配置

{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*", "ServiceDiscovery": {
"ServiceName": "A",
"Consul": {
"HttpEndpoint": "http://192.168.74.161:8500"
}
}
}

这里服务注册就算完成

Ocelot网关搭建

接下来继续Ocelot借助于Consul实现服务发现

新建项目Ocelot.Gateway

将以下依赖加入Ocelot.Gateway.csproj中:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Ocelot" Version="12.0.1" />
<PackageReference Include="Ocelot.Provider.Consul" Version="0.1.2" />
</ItemGroup> <ItemGroup>
<Content Update="ocelot.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup> </Project>

新建ocelot.json文件

{
"ReRoutes": [
{
"UseServiceDiscovery": true,
"DownstreamPathTemplate": "/{url}",
"DownstreamScheme": "http",
"ServiceName": "A",
"LoadBalancerOptions": {
"Type": "RoundRobin"
},
"UpstreamPathTemplate": "/a/{url}",
"UpstreamHttpMethod": [ "Get", "Post" ],
"ReRoutesCaseSensitive": false
}
],
"GlobalConfiguration": {
// 使用Consul服务治理
"ServiceDiscoveryProvider": {
"Host": "192.168.74.161",
"Port": ,
"ConfigurationKey": "Oceolot_A" //存储在Consul上的Key
}
}
}

修改Startup.cs文件如下:

   public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
} public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services.AddOcelot(
new ConfigurationBuilder()
.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true).Build())
.AddConsul()
.AddConfigStoredInConsul();
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
} app.UseHttpsRedirection();
app.UseOcelot().Wait();
}
}

发布WebA后复制两份分别启动

dotnet WebA.dll --urls="http://0.0.0.0:2001"

dotnet WebA.dll --urls="http://0.0.0.0:2002"

到这里相当于2001和2002程序简单集群了一下

可以发现日志中有 http://192.168.74.161:2002/HealthCheck调用信息:

这其实是consul进行健康检查进行的调用。

启动多个程序后,打开浏览器打开Consuld界面会发现注册了两个服务

这里ocelot网关和consul的服务注册和发现就算初步集成。

生产部署

如果生产环境是windows的情况,将consul做成windwos服务即可

sc create "ConsulServer" binPath="F:\XXX\consul.exe agent -config-dir XXX.json"

生产环境是linux则借助systemd做成守护进程即可

生产环境是docker,运行以下命令部署单节点,集群类似

docker run --restart=always -d --name=c13 -p : consul agent -server -bootstrap -ui -data-dir tmp/consul -bind 0.0.0.0 -client 0.0.0.0 -node dockerserver

目前集群搭建成功,但是连接的话如果指定某个端点的ip进行连接,端点宕机,就会导致网关一样无法连接consul进行服务发现。所以还需进行配置暴露一个端点让客户端连接,配置详情:https://www.consul.io/docs/connect/configuration.html

不过也可以做成虚拟ip进行多台consul的负载。客户端连接虚拟ip即可

项目地址:

github地址

微服务之:从零搭建ocelot网关和consul集群的更多相关文章

  1. 庐山真面目之十微服务架构 Net Core 基于 Docker 容器部署 Nginx 集群

    庐山真面目之十微服务架构 Net Core 基于 Docker 容器部署 Nginx 集群 一.简介      前面的两篇文章,我们已经介绍了Net Core项目基于Docker容器部署在Linux服 ...

  2. 【微服务架构】SpringCloud之Eureka(注册中心集群篇)(三)

    上一篇讲解了spring注册中心(eureka),但是存在一个单点故障的问题,一个注册中心远远无法满足实际的生产环境,那么我们需要多个注册中心进行集群,达到真正的高可用.今天我们实战来搭建一个Eure ...

  3. 庐山真面目之十二微服务架构基于Docker搭建Consul集群、Ocelot网关集群和IdentityServer版本实现

    庐山真面目之十二微服务架构基于Docker搭建Consul集群.Ocelot网关集群和IdentityServer版本实现 一.简介      在第七篇文章<庐山真面目之七微服务架构Consul ...

  4. 庐山真面目之六微服务架构Consul集群、Ocelot网关集群和Nginx版本实现

    庐山真面目之六微服务架构Consul集群.Ocelot网关集群和Nginx版本实现 一.简介      在上一篇文章<庐山真面目之五微服务架构Consul集群.Ocelot网关和Nginx版本实 ...

  5. 庐山真面目之七微服务架构Consul集群、Ocelot网关集群和IdentityServer4版本实现

    庐山真面目之七微服务架构Consul集群.Ocelot网关集群和IdentityServer4版本实现 一.简介      在上一篇文章<庐山真面目之六微服务架构Consul集群.Ocelot网 ...

  6. ASP.NET Core微服务+Tabler前端框架搭建个人博客2--系统架构

    功能分析 在整个微服务架构的搭建过程中,我们需要做的第一步就是对服务进行拆分,将一个完整的系统模块化,通过对各个模块互联,共同完成一个系统的工作.既然要做到模块化,那么必须明白你的系统的需求到底是什么 ...

  7. 【NET CORE微服务一条龙应用】第一章 网关使用与配置

    简介 微服务的系统应用中,网关系统使用的是ocelot,ocelot目前已经比较成熟了 ocelot就不做介绍了,等整体介绍完后再进行各类扩展介绍,ocelot源码地址:https://github. ...

  8. 8分钟学会Consul集群搭建及微服务概念

    Consul介绍: Consul 是由 HashiCorp 公司推出的开源软件,用于实现分布式系统的服务发现与配置.与其他分布式服务注册与发现的方案,Consul 的方案更“一站式”,内置了服务注册与 ...

  9. Ocelot+Consul 集群搭建实践

    博客园已经有很多大神写过consul集群搭建了.大家都在玩,那我也不能托后退呢 不过自己研究下还是好的.毕竟每个人遇到的问题的不同 研究过才能说自己玩过consul,文章有部分名词解释是收集网络 Co ...

随机推荐

  1. 关于一体机打印新加菜按钮更改为下单小票打印设置FAQ(适用正餐6.0.1.0+,轻餐4.0.6.2+)

    适用版本:正餐6.0.1.0+,轻餐4.0.6.2+ 实际场景:更新后小票设置中的打印新加菜按钮更换为下单小票打印设置,更换后,设置中,有3个选项: 1.仅打印新加菜    (选中后,订单加菜后前台小 ...

  2. NumPy的使用(一)

    # -*- coding: utf8 -*- from numpy import* a=arange(15).reshape(3,5) print a print a.shape print a.nd ...

  3. spring-AOP(面向切面编程)-xml方式配置

    AOP是针对面向对象编程的一种补充,有时使用面向对象不能很好完成一些额外的功能业务时,可以采用AOP来进行补充. AOP术语: 切面(Aspect) 切面是用于编写切面逻辑的一个类,这个类很类似于JD ...

  4. Java的sql动态参数

    在C#的方法中可以使用params Parameter[] values来动态获取sql语句中的参数值数组.Java中可以自己封装出一个类似于C#的方法 1.获取结果集 /** * 获取结果集 * @ ...

  5. SQL Server 索引重建手册

    注意: 索引重建前建议把数据库切换为完整模式,否则索引复制会在数据文件中进行,导致数据文件很大,而数据文件的收缩比日志文件的收缩要困难的多,且会对业务造成影响. 步骤一: 查询索引碎片,脚本如下,库比 ...

  6. Mac轻量级服务器http-server

    刚想跑个Vue页面,发现我本地没有应用服务器(Tomcat/IIS...) 于是想下载了Tomcat,才发现我没有装JDK,而Mac的JDK下得好久,都下不下来,想想算了. 于是在网上找个轻量级的服务 ...

  7. openPose-注

    静态编译出错:MD能通过 \ https://blog.csdn.net/Silver_sail/article/details/40540887 E:\project\BodyPoseEstimat ...

  8. [Java] SpringMVC工作原理之二:HandlerMapping和HandlerAdapter

    一.HandlerMapping 作用是根据当前请求的找到对应的 Handler,并将 Handler(执行程序)与一堆 HandlerInterceptor(拦截器)封装到 HandlerExecu ...

  9. 获取WebApplicationContext的几种方式

    加载WebApplicationContext的方式 WebApplicationContext是ApplicationContext的子接口,纵观Spring框架的几种容器,BeanFactory作 ...

  10. 【转】vue父子组件之间的通信

    vue父子组件之间的通信 在vue组件通信中其中最常见通信方式就是父子组件之中的通性,而父子组件的设定方式在不同情况下又各有不同.最常见的就是父组件为控制组件子组件为视图组件.父组件传递数据给子组件使 ...