一、简介
在上一篇文章《庐山真面目之微服务的简介和技术栈》中,我们已经探讨了微服务的来龙去脉,也说了想要实现微服务架构所需要的技术栈,今天我们开始实现一个微服务,当然这个实现是简化版本的,在这个版本里面也不涉及 Docker、K8S等的东西,我们逐步演化,今天这一期只是实现一个NGINX版本的微服务的功能。
1、说明
有关微服务架构所涉及的技术太多,无法再一篇文章内讨论完全,所以,我们就分多期来说,每期都递进相关的技术,然后,一步一步的演化而来。如果您是大牛,就可以直接跳过,因为这些东西相对于您来说,这个太简单了。特别说明,这里的所有代码都经过测试,所以大家可以放心使用。
2、开发环境
以下就是开发环境,不用多说,都很简单,一看就知道。
(1)、开发工具:Visual
Studio 2019
(2)、开发语言:C#
(3)、开发平台:Net
Core3.1,跨平台。
(4)、网关服务:NGINX,专注于高性能网关。
3、今天的目标
今天我们的目标就是建立一个基于Nginx网关实现的,服务实例没有任何容器包容,只是独立进程承载的这么一个架构实现。
二、微服务架构之NGINX 版本实现
在文章开始之前,我们还是要简要说明一下。上一篇文件《庐山真面目之微服务的简介和技术栈》中我们说过,微服务有三个版本,分别是:单体架构、垂直拆分设计和微服务,基于SOA的我们暂时不讨论。其实,第二版本和第一个没有本质区别,都是单体架构而已,所以,我们今天就简单实现一下微服务的版本,由于里面涉及的技术很多,微服务这个版本我又分了多个版本来写,今天是最简单。
今天我们主要讨论基于NGINX实现的分布式、微服务架构的优缺点,每个项目的代码都独立贴出来,逻辑很简单,因为我们侧重架构嘛,我们开始吧。
1、我们解决方案,包含5个项目。
(1)、PatrickLiu.MicroService.Client(ASP.NET CORE MVC),客户端应用程序。
这个项目很简单,几乎没有任何修改,只是在这里访问服务实例而已。
1)、startup.cs 类中唯一增加的代码
1 public class Startup
2 {
3
4 /// <summary>
5 /// 注册服务到容器中。
6 /// </summary>
7 /// <param name="services"></param>
8 public void ConfigureServices(IServiceCollection services)
9 {
10 services.AddSingleton<IUserService, UserService>();
11 }
12 }
2)、HomeController.cs 类的代码
1 public class HomeController : Controller
2 {
3 private readonly ILogger<HomeController> _logger;
4 private readonly IUserService _userService;
5 private static int index;
6
7 /// <summary>
8 /// 初始化该类型的新实例。
9 /// </summary>
10 /// <param name="logger">注入日志对象。</param>
11 /// <param name="userService">注入用户服务对象。</param>
12 public HomeController(ILogger<HomeController> logger, IUserService userService)
13 {
14 _logger = logger;
15 _userService = userService;
16 }
17
18 /// <summary>
19 /// 首页。
20 /// </summary>
21 /// <returns></returns>
22 public IActionResult Index()
23 {
24 #region 1、单体架构
25
26 //this.ViewBag.Users = _userService.UserAll();
27
28 #endregion
29
30 #region 2、分布式架构
31
32 #region 2.1、直接访问服务实例
33
34 //string url = string.Empty;
35 //url = "http://localhost:5726/api/users/all";
36 //url = "http://localhost:5726/api/users/all";
37 //url = "http://localhost:5726/api/users/all";
38
39 #endregion
40
41 #region 通过 Ngnix网关访问服务实例,默认轮训。
42
43 string url = "http://localhost:8080/api/users/all";
44
45 #endregion
46
47 string content = InvokeAPI(url);
48 this.ViewBag.Users = Newtonsoft.Json.JsonConvert.DeserializeObject<IEnumerable<User>>(content);
49 Console.WriteLine($"This is {url} Invoke.");
50
51 #endregion
52
53 return View();
54 }
55
56
57 /// <summary>
58 ///
59 /// </summary>
60 /// <param name="url"></param>
61 /// <returns></returns>
62 public static string InvokeAPI(string url)
63 {
64 using (HttpClient client = new HttpClient())
65 {
66 HttpRequestMessage message = new HttpRequestMessage();
67 message.Method = HttpMethod.Get;
68 message.RequestUri = new Uri(url);
69 var result = client.SendAsync(message).Result;
70 string conent = result.Content.ReadAsStringAsync().Result;
71 return conent;
72 }
73 }
74 }
75 }
3)、Index.cshtml 视图的代码
1 @{
2 ViewData["Title"] = "Home Page";
3 }
4
5 <div class="text-center">
6 <h1 class="display-4">Welcome</h1>
7 <ul>
8 @{
9
10 foreach (var item in ViewBag.Users)
11 {
12 <li>@item.ID --@item.Name --@item.Role </li>
13 }
14 }
15 </ul>
16 <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
17 </div>
(2)、PatrickLiu.MicroService.Interfaces(NETCORE类库项目),定义服务接口。
这个项目很简单,只定义了一个接口类型,名称:IUserService.cs。
IUserService的代码
1 using PatrickLiu.MicroService.Models;
2 using System.Collections.Generic;
3
4 namespace PatrickLiu.MicroService.Interfaces
5 {
6 /// <summary>
7 /// 用户服务的接口定义。
8 /// </summary>
9 public interface IUserService
10 {
11 /// <summary>
12 /// 查找指定主键的用户实例对象。
13 /// </summary>
14 /// <param name="id">用户的主键。</param>
15 /// <returns>返回查找到的用户实例对象。</returns>
16 User FindUser(int id);
17
18 /// <summary>
19 /// 获取所有用户的实例集合。
20 /// </summary>
21 /// <returns>返回所有的用户实例。</returns>
22 IEnumerable<User> UserAll();
23 }
24 }
(3)、PatrickLiu.MicroService.Models
(NETCORE类库项目),定义实体类模型。
这个项目很简单,只定义了一个实体类型,类名:User.cs。
User.cs 的代码
1 using System;
2
3 namespace PatrickLiu.MicroService.Models
4 {
5 /// <summary>
6 /// 用户模型。
7 /// </summary>
8 public class User
9 {
10 /// <summary>
11 /// 获取或者设置用户主键。
12 /// </summary>
13 public int ID { get; set; }
14
15 /// <summary>
16 /// 获取或者设置用户姓名。
17 /// </summary>
18 public string Name { get; set; }
19
20 /// <summary>
21 /// 获取或者设置用户账号名称。
22 /// </summary>
23 public string Account { get; set; }
24
25 /// <summary>
26 /// 获取或者设置用户密码。
27 /// </summary>
28 public string Password { get; set; }
29
30 /// <summary>
31 /// 获取或者设置用户的电子邮箱地址。
32 /// </summary>
33 public string Email { get; set; }
34
35 /// <summary>
36 /// 获取或者设置用户角色。
37 /// </summary>
38 public string Role { get; set; }
39
40 /// <summary>
41 /// 获取或者设置用户的登录时间。
42 /// </summary>
43 public DateTime LoginTime { get; set; }
44 }
45 }
(4)、PatrickLiu.MicroService.Services(NetCore 类库项目),实现接口类型。
这个项目很简单,只定义了一个类型,实现IUserService接口,类名:UserService.cs。
UserService.cs的代码
1 using PatrickLiu.MicroService.Interfaces;
2 using PatrickLiu.MicroService.Models;
3 using System;
4 using System.Collections.Generic;
5 using System.Linq;
6
7 namespace PatrickLiu.MicroService.Services
8 {
9 /// <summary>
10 /// 实现用户服务接口的实现类型。
11 /// </summary>
12 public class UserService : IUserService
13 {
14 private IList<User> dataList;
15
16 /// <summary>
17 /// 初始化类型的实例
18 /// </summary>
19 public UserService()
20 {
21 dataList = new List<User>()
22 { new User {ID=1,Name="黄飞鸿",Account="HuangFeiHong",Password="HuangFeiHong123456",Email="huangFeiHong@sina.com", Role="Admin", LoginTime=DateTime.Now },
23 new User {ID=2,Name="洪熙官",Account="HongXiGuan",Password="HongXiGuan54667",Email="HongXiGuan@sina.com", Role="Admin", LoginTime=DateTime.Now.AddDays(-5) },
24 new User {ID=3,Name="方世玉",Account="FangShiYu",Password="FangShiYu112233",Email="fangShiYu@163.com", Role="Admin", LoginTime=DateTime.Now.AddDays(-30) },
25 new User {ID=4,Name="苗翠花",Account="MiaoCuiHua",Password="MiaoCuiHua887766",Email="miaoCuiHua@sohu.com", Role="Admin", LoginTime=DateTime.Now.AddDays(-90) },
26 new User {ID=5,Name="严咏春",Account="YanYongChun",Password="YanYongChun09392",Email="yanYongChun@263.com", Role="Admin", LoginTime=DateTime.Now.AddMinutes(-50) }};
27 }
28
29 /// <summary>
30 /// 查找指定主键的用户实例对象。
31 /// </summary>
32 /// <param name="id">用户的主键。</param>
33 /// <returns>返回查找到的用户实例对象。</returns>
34 public User FindUser(int id)
35 {
36 return dataList.FirstOrDefault(user => user.ID == id);
37 }
38
39 /// <summary>
40 /// 获取所有用户的实例集合。
41 /// </summary>
42 /// <returns>返回所有的用户实例。</returns>
43 public IEnumerable<User> UserAll()
44 {
45 return dataList;
46 }
47 }
48 }
(5)、PatrickLiu.MicroService.ServiceInstance(ASP.NET CORE WEB API项目)。
这个项目很简单,引用其他三个项目,制作
Restfull API,可以让客户端访问。
引用项目:PatrickLiu.MicroService.Interfaces
PatrickLiu.MicroService.Services
PatrickLiu.MicroService.Models
1)、Startup.cs 的代码
1 public class Startup
2 {
3
4 /// <summary>
5 ///
6 /// </summary>
7 /// <param name="services"></param>
8 public void ConfigureServices(IServiceCollection services)
9 {
10 services.AddControllers();
11 services.AddSingleton<IUserService, UserService>();
12 }
13 }
2)、Program.cs 的代码
1 public class Program
2 {
3 public static void Main(string[] args)
4 {
5 new ConfigurationBuilder()
6 .SetBasePath(Directory.GetCurrentDirectory())
7 .AddCommandLine(args)//支持命令行
8 .Build();
9
10 CreateHostBuilder(args).Build().Run();
11 }
12
13 public static IHostBuilder CreateHostBuilder(string[] args) =>
14 Host.CreateDefaultBuilder(args)
15 .ConfigureWebHostDefaults(webBuilder =>
16 {
17 webBuilder.UseStartup<Startup>();
18 });
19 }
3)、UsersController.cs 的代码
1 /// <summary>
2 /// 用户的 API 类型。
3 /// </summary>
4 [Route("api/[controller]")]
5 [ApiController]
6 public class UsersController : ControllerBase
7 {
8 #region 私有字段
9
10 private readonly ILogger<UsersController> _logger;
11 private readonly IUserService _userService;
12 private IConfiguration _configuration;
13
14 #endregion
15
16 #region 构造函数
17
18 /// <summary>
19 /// 初始化该类型的新实例。
20 /// </summary>
21 /// <param name="logger">日志记录器。</param>
22 /// <param name="userService">用户服务接口。</param>
23 /// <param name="configuration">配置服务。</param>
24 public UsersController(ILogger<UsersController> logger, IUserService userService, IConfiguration configuration)
25 {
26 _logger = logger;
27 _userService = userService;
28 _configuration = configuration;
29 }
30
31 #endregion
32
33 #region 实例方法
34
35 /// <summary>
36 /// 获取一条记录
37 /// </summary>
38 /// <param name="id"></param>
39 /// <returns></returns>
40 [HttpGet]
41 [Route("Get")]
42 public User Get(int id)
43 {
44 return _userService.FindUser(id);
45 }
46
47 /// <summary>
48 /// 获取所有记录。
49 /// </summary>
50 /// <returns></returns>
51 [HttpGet]
52 [Route("All")]
53 //[Authorize]
54 public IEnumerable<User> Get()
55 {
56 Console.WriteLine($"This is UsersController {this._configuration["port"]} Invoke");
57
58 return this._userService.UserAll().Select((user => new User
59 {
60 ID = user.ID,
61 Name = user.Name,
62 Account = user.Account,
63 Password = user.Password,
64 Email = user.Email,
65 Role = $"{this._configuration["ip"]}:{this._configuration["port"]}",
66 LoginTime = user.LoginTime
67 })); ;
68 }
69
70 /// <summary>
71 /// 超时处理
72 /// </summary>
73 /// <returns></returns>
74 [HttpGet]
75 [Route("Timeout")]
76 public IEnumerable<User> Timeout()
77 {
78 Console.WriteLine($"This is Timeout Start");
79 //超时设置。
80 Thread.Sleep(3000);
81
82 Console.WriteLine($"This is Timeout End");
83
84 return this._userService.UserAll().Select((user => new User
85 {
86 ID = user.ID,
87 Name = user.Name,
88 Account = user.Account,
89 Password = user.Password,
90 Email = user.Email,
91 Role = $"{this._configuration["ip"]}:{this._configuration["port"]}",
92 LoginTime = user.LoginTime
93 })); ;
94 }
95
96 #endregion
97 }
2、编译项目,启动四个服务实例。
这四个服务实例是PatrickLiu.MicroService.ServiceInstance项目的实例,执行 dotnet 命令要在当前目录下。
我的目录:E:\Visual Studio 2019\Project\SourceCode\PatrickLiu.MicroService\PatrickLiu.MicroService.ServiceInstance\bin\Debug\netcoreapp3.1
(1)、dotnet
PatrickLiu.MicroService.ServiceInstance.dll --urls="http://*:5726"
--ip="127.0.0.1" --port=5726
可以访问WebAPI地址,验证是否成功。
地址:http://localhost:5726/api/users/all
效果如图:
(2)、dotnet
PatrickLiu.MicroService.ServiceInstance.dll --urls="http://*:5727"
--ip="127.0.0.1" --port=5727
可以访问WebAPI地址,验证是否成功。
地址:http://localhost:5727/api/users/all
效果如图:
(3)、dotnet
PatrickLiu.MicroService.ServiceInstance.dll --urls="http://*:5728"
--ip="127.0.0.1" --port=5728
可以访问WebAPI地址,验证是否成功。
地址:http://localhost:5728/api/users/all
效果如图:
(4)、dotnet PatrickLiu.MicroService.ServiceInstance.dll
--urls="http://*:5729" --ip="127.0.0.1" --port=5729
可以访问WebAPI地址,验证是否成功。
地址:http://localhost:5729/api/users/all
效果如图:
3、下载NGINX 服务组件,默认下载
Windows 版本。
官网: http://nginx.org/en/download.html
4、部署NGINX服务器。
将下载的文件拷贝到没有中文的目录下,解压文件就可以。
我的存放目录:D:\Programs\MicroServices
5、修改 NGINX.CONF 文件。
修改该目录D:\Programs\MicroServices\Nginx-1.18.0\conf
下的配置文件。文件名:nginx.conf
增加的配置内容如下:
1 upstream MicroService{
2 server localhost:5726;
3 server localhost:5727;
4 server localhost:5728;
5 server localhost:5729;
6 }
7
8 server {
9 listen 8080;
10 server_name localhost;
11
12 location / {
13 proxy_pass http://MicroService;
14 }
15 }
6、启动 Nginx 服务器。
注意:我是在Nginx当前目录下边。
Start nginx
NGINX端口默认:80,我改成了8080,没有提示,一般会启动正常。
可以访问NGINX地址,验证NGINX是否配置并且启动成功。
地址:http://localhost:8080
效果如图:
7、打开浏览器,输入地址:http://localhost:8080/api/users/all,多次刷新页面,你就会看到变化。我们已经实现了分布式、负载均衡。
如图:5726 端口
如图:5727端口
如图:5728端口
如图:5729端口
8、我们测试NGINX的高可用和可扩展性,得出以下结论。
(1)、Nginx 客户端配置很简单,直接访问 Nginx 的网关地址就会路由到注册服务实例。
(2)、如果服务实例掉线或者出现异常,可以自动察觉器状况,下次轮训可以跳过,不需人为参与。
(3)、如果系统增加了新的服务实例,Nginx 无法自动发现,需要人工修改配置文件,然后重启,才可以。
由于第三点的缺点,是我们这个版本的最大的缺点,我们不可能在庞大的系统中总是通过人力来做这些事。无法自动发现服务,我们需要继续改进,那就是服务注册发现中心。
三、 结束语
好了,今天就写到这里了,这个是介于分布式和微服务之间的一个很简单的架构实现,虽然很简单,但是我们所要表达的思想和所要获取到的东西我们已经得到了。什么东西都是由简入繁的,下一期,继续开始我们的有关微服务的进化吧。努力吧,每天进步一点点。
庐山真面目之二微服务架构NGINX版本实现的更多相关文章
-
庐山真面目之三微服务架构Consul版本实现
庐山真面目之三微服务架构Consul版本实现 一.简介 在上一篇文章<庐山真面目之二微服务架构NGINX版本实现>中,我们已经探讨了如何搭建基于Nginx 网关的微服务 ...
-
庐山真面目之十二微服务架构基于Docker搭建Consul集群、Ocelot网关集群和IdentityServer版本实现
庐山真面目之十二微服务架构基于Docker搭建Consul集群.Ocelot网关集群和IdentityServer版本实现 一.简介 在第七篇文章<庐山真面目之七微服务架构Consul ...
-
庐山真面目之十微服务架构 Net Core 基于 Docker 容器部署 Nginx 集群
庐山真面目之十微服务架构 Net Core 基于 Docker 容器部署 Nginx 集群 一.简介 前面的两篇文章,我们已经介绍了Net Core项目基于Docker容器部署在Linux服 ...
-
庐山真面目之十一微服务架构手把手教你搭建基于Jenkins的企业级CI/CD环境
庐山真面目之十一微服务架构手把手教你搭建基于Jenkins的企业级CI/CD环境 一.介绍 说起微服务架构来,有一个环节是少不了的,那就是CI/CD持续集成的环境.当然,搭建CI/CD环境的工具很多, ...
-
庐山真面目之九微服务架构 NetCore 基于 Docker 基础镜像和挂载文件部署
庐山真面目之九微服务架构 NetCore 基于 Docker 基础镜像和挂载文件部署 一.简介 我们在上一篇文章<庐山真面目之八微服务架构 NetCore 基于 Dockerfile ...
-
springcloud(二) 微服务架构编码构建
微服务架构编码构建 1 基础知识 1.1 版本 2 微服务cloud整体聚合父工程Project 2.1 new project 2.2 字符编码设置 utf-8 2.3 pom.xml 2.4 父工 ...
-
庐山真面目之十三微服务架构中如何在Docker上使用Redis缓存
一.介绍 1.开始说明 在微服务器架构中,有一个组件是不能少的,那就是缓存组件.其实来说,缓存组件,这个叫法不是完全正确,因为除了缓存功能,它还能完成其他很多功能.我就不隐瞒了,今天我们要探讨 ...
-
庐山真面目之六微服务架构Consul集群、Ocelot网关集群和Nginx版本实现
庐山真面目之六微服务架构Consul集群.Ocelot网关集群和Nginx版本实现 一.简介 在上一篇文章<庐山真面目之五微服务架构Consul集群.Ocelot网关和Nginx版本实 ...
-
庐山真面目之七微服务架构Consul集群、Ocelot网关集群和IdentityServer4版本实现
庐山真面目之七微服务架构Consul集群.Ocelot网关集群和IdentityServer4版本实现 一.简介 在上一篇文章<庐山真面目之六微服务架构Consul集群.Ocelot网 ...
随机推荐
-
C++学习之静态成员
一.静态数据成员 C++允许将类的数据成员定义为静态成员.静态数据成员是属于类的,整个类只有一个备份,相当于类的全局变量,能够被该类的所有对象共用. 1.静态成员的声明 在类数据成员的声明前加上关键字 ...
-
VS常用技巧
VS2005代码编辑器的展开和折叠代码确实很方便和实用.以下是展开代码和折叠代码所用到的快捷键,很常用: Ctrl + M + O: 折叠所有方法 Ctrl + M + M: 折叠或者展开当前方法 C ...
-
PreparedStatement執行sql語句
import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import org ...
-
.NET Core + Ocelot + IdentityServer4 + Consul 基础架构实现
先决条件 关于 Ocelot 针对使用 .NET 开发微服务架构或者面向服务架构提供一个统一访问系统的组件. 参考 本文将使用 Ocelot 构建统一入口的 Gateway. 关于 IdentityS ...
-
MR1和MR2(Yarn)工作原理流程
一.Mapreduce1 图1 MR1工作原理图 工作流程主要分为以下6个步骤: 1 作业的提交 1)客户端向jobtracker请求一个新的作业ID(通过JobTracker的getNewJobI ...
-
Flink运行在yarn上
在一个企业中,为了最大化的利用集群资源,一般都会在一个集群中同时运行多种类型的 Workload.因此 Flink 也支持在 Yarn 上面运行: flink on yarn的前提是:hdfs.yar ...
-
ASP.NET Forms验证
/// <summary> /// 执行用户登录操作 /// </summary> /// <param name="config">授权配置信 ...
-
windows下一分钟配置ngnix实现HLS m3u8点播
1. 下载 nginx-1.5.10 for windows 2. 修改配置文件nginx-1.5.10\conf\nginx.conf,增加以下行到最后一个"}"的前一行: lo ...
-
C中的volatile用法[转载]
volatile 影响编译器编译的结果,指出,volatile 变量是随时可能发生变化的,与volatile变量有关的运算,不要进行编译优化,以免出错,(VC++ 在产生release版可执行码时会进 ...
-
YAML文件中在单一文件中区分多个文件
1.在单一文件中,可用连续三个连字号(---)区分多个文件. 2.另外,还有选择性的连续三个点号( ... )用来表示文件结尾. 题外:YAML其实语法很多也很灵活,但是针对Spring支持的语法其实 ...