一、简介

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

    Lyndon Word 定义 对于字符串 \(S\),若 \(S\) 的最小后缀为其本身,那么称 \(S\) 为 \(\text{Lyndon}\) 串(\(\text{Lyndon Word}\)) ...

  2. 020 01 Android 零基础入门 01 Java基础语法 02 Java常量与变量 14 变量与常量 知识总结

    020 01 Android 零基础入门 01 Java基础语法 02 Java常量与变量 14 变量与常量 知识总结 本文知识点:变量与常量 知识总结 Java中的标识符 Java中的关键字 目前常 ...

  3. sklearn训练模型的保存与加载

    使用joblib模块保存于加载模型 在机器学习的过程中,我们会进行模型的训练,最常用的就是sklearn中的库,而对于训练好的模型,我们当然是要进行保存的,不然下次需要进行预测的时候就需要重新再进行训 ...

  4. JavaScript返回当前的时分秒

    要求: 封装一个函数返回当前的时分秒 格式 08:08:08 代码实现: function getTimer() { var time = new Date(); var h = time.getHo ...

  5. git pull设置为无需密码

    https方式每次都要输入密码,按照如下设置即可输入一次就不用再手输入密码的困扰而且又享受https带来的极速 设置记住密码(默认15分钟): git config --global credenti ...

  6. OpenSSL加密系统简介

    加密基本原理 OpenSSL移植到arm开发板参考  http://blog.chinaunix.net/uid-27717694-id-3530600.html 1.公钥和私钥: 公钥和私钥就是俗称 ...

  7. Mac zsh中所有命令失效

    参考文章 https://blog.csdn.net/hujincai_55/article/details/95680245?utm_medium=distribute.pc_relevant.no ...

  8. MySQL数据库规范 (设计规范+设计规范+操作规范)

    I 文档定义 1.1 编写目的 为了在软件生命周期内规范数据库相关的需求分析.设计.开发.测试.运维工作,便于不同团队之间的沟通协调,以及在相关规范上达成共识,提升相关环节的工作效率和系统的可维护性. ...

  9. JAVA Schedule的Cron表达式

    spring中用到的定时任务,一般用到的有Timer()和Schedule Cron表达式一般是程序的定时任务中所要起的..我们用的springboot中的@Schedule中,启动类中添加enabl ...

  10. selenium常用操作学习笔记

    一,弹窗处理(推荐文章:https://blog.csdn.net/huilan_same/article/details/52298460) selenium提供switch_to方法定位弹窗的对话 ...