一、简介

         在上一篇文章《庐山真面目之微服务的简介和技术栈》中,我们已经探讨了微服务的来龙去脉,也说了想要实现微服务架构所需要的技术栈,今天我们开始实现一个微服务,当然这个实现是简化版本的,在这个版本里面也不涉及 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版本实现的更多相关文章

  1. 庐山真面目之三微服务架构Consul版本实现

    庐山真面目之三微服务架构Consul版本实现 一.简介           在上一篇文章<庐山真面目之二微服务架构NGINX版本实现>中,我们已经探讨了如何搭建基于Nginx 网关的微服务 ...

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

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

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

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

  4. 庐山真面目之十一微服务架构手把手教你搭建基于Jenkins的企业级CI/CD环境

    庐山真面目之十一微服务架构手把手教你搭建基于Jenkins的企业级CI/CD环境 一.介绍 说起微服务架构来,有一个环节是少不了的,那就是CI/CD持续集成的环境.当然,搭建CI/CD环境的工具很多, ...

  5. 庐山真面目之九微服务架构 NetCore 基于 Docker 基础镜像和挂载文件部署

    庐山真面目之九微服务架构 NetCore 基于 Docker 基础镜像和挂载文件部署 一.简介      我们在上一篇文章<庐山真面目之八微服务架构 NetCore 基于 Dockerfile ...

  6. springcloud(二) 微服务架构编码构建

    微服务架构编码构建 1 基础知识 1.1 版本 2 微服务cloud整体聚合父工程Project 2.1 new project 2.2 字符编码设置 utf-8 2.3 pom.xml 2.4 父工 ...

  7. 庐山真面目之十三微服务架构中如何在Docker上使用Redis缓存

    一.介绍     1.开始说明 在微服务器架构中,有一个组件是不能少的,那就是缓存组件.其实来说,缓存组件,这个叫法不是完全正确,因为除了缓存功能,它还能完成其他很多功能.我就不隐瞒了,今天我们要探讨 ...

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

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

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

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

随机推荐

  1. 一种基于均值不等式的Listwise损失函数

    一种基于均值不等式的Listwise损失函数 1 前言 1.1 Learning to Rank 简介 Learning to Rank (LTR) , 也被叫做排序学习, 是搜索中的重要技术, 其目 ...

  2. 003 01 Android 零基础入门 01 Java基础语法 01 Java初识 03 Java程序的执行流程

    003 01 Android 零基础入门 01 Java基础语法 01 Java初识 03 Java程序的执行流程 Java程序长啥样? 首先编写一个Java程序 记事本编写程序 打开记事本 1.wi ...

  3. 《C++primerplus》第6章练习题

    本来前面五题都做完了,写博客时没保存好草稿= =,写了个整合版的程序,实现前五题的关键部分. 1.定义一个叫jojo的结构,存储姓名.替身和力量值,使用动态结构数组初始化二乔.承太郎和乔鲁诺乔巴纳等人 ...

  4. 1.入门篇十分钟了解Spring Cloud

    文章目录 Spring Cloud入门系列汇总 为什么需要学习Spring Cloud 什么是Spring Cloud 设计目标与优缺点 设计目标 优缺点 Spring Cloud发展前景 整体架构 ...

  5. golang API 请求队列

    概要 实现思路 使用方法 启动队列服务 使用队列服务 概要 在调用第三方 API 的时候, 基本都有访问限速的限制条件. 第三方的 API 有多个的时候, 就不太好控制访问速度, 常常会导致 HTTP ...

  6. DM9000裸机驱动程序设计

    对于任何一个硬件模块的设计,首先第一步都是要先了解硬件本身后,再开始程序的软件设计.而由于DM9000的芯片文档内容很多,要驱动好网卡,需要很长时间,特别对于新手比较困难,所以可以参考linux内核代 ...

  7. MeteoInfo脚本示例:GrADS to netCDF

    这里给出一个将GrADS数据文件转为netCDF数据文件的脚本示例程序,其它格式数据转netCDF可以参考: #-------------------------------------------- ...

  8. c# 常用帮助类

    C#常用帮助类 因为小土现在还是处于小白阶段,所以自己的知识技术还达不到要求,但是小土在网上找到一个大神的,等以后小土技术有了一定提升以后,在走自己的路,啥也不说了上货. 地址 :https://gi ...

  9. 扫描仪扫描文件处理-ABBYY对扫描版PDF文字加黑加粗、去除背景漂白

    1. 设置ABBYY自动歪斜矫正: 2. 设置导出PDF参数: 3. PDF文字加黑加粗.去除背景漂白步骤:3.1 ABBYY - 打开扫描版PDF文档3.2 ABBYY - 编辑图像3.3 等级 - ...

  10. request-html 使用

    from requests_html import HTMLSessionsession = HTMLSession()resp = session.get('http://www.spbeen.co ...