zoukankan      html  css  js  c++  java
  • 基于.NET CORE微服务框架 -surging的介绍和简单示例 (开源)

    一、前言

            至今为止编程开发已经11个年头,从 VB6.0,ASP时代到ASP.NET再到MVC, 从中见证了.NET技术发展,从无畏无知的懵懂少年,到现在的中年大叔,从中的酸甜苦辣也只有本人自知。随着岁月的成长,技术也从原来的三层设计到现在的领域驱动设计,从原来的关系型数据库SQL 2000到现在的NOSQL (mongodb,couchbase,redis),从原来基于SOAP协议的web service到现在基于restful 协议的web api,wcf,再到现在rpc微服务。技术的成长也带来岁月的痕迹。

            现在微软又出了.NET CORE,为了紧跟微软的步伐,研究了将近1年,从中看了不少开源代码,如NetEscapades.Configuration,eShopOnContainers,rabbit.RPC等等,从中学到了不少知识,后面利用所学加上自己的想法,开发出分布式微服务框架surging。开源地址:点击打开链接。下面会以三篇文章的形式介绍

    surging

    1.基于.NET CORE微服务框架 -surging的介绍和简单示例 (开源)

    2.剥析surging的架构思想

    3.后续surging的架构完善工作

    二、什么是surging

    surging从中文译义来说,冲击,汹涌,也可以翻译成风起云涌。我所希望的是.net core 能成为最流行的技术。

    surging从技术层面来说就是基于RPC协议的分布式微服务技术框架,框架依赖于Netty 进行异步通信,采用Zookeeper作为服务注册中心,集成了哈希,随机和轮询作为负载均衡算法

    1.服务化应用基本框架

    框架的执行过程如下:

    1.服务提供者启动,根据RPC协议通过配置的IP和port绑定到netty上

    2.注册服务信息存储至Zookeeper

    3.客户端CreateProxy调用服务时,从内存中拿到上次通知的所有效的服务地址,根据路由信息和负载均衡机制选择最终调用的服务地址,发起调用

    2.简单示例

      创建IModuleServices

       IUserService.cs:

      [ServiceBundle]  //服务标记
        public interface IUserService
        {
            Task<string> GetUserName(int id);
    
            Task<bool> Exists(int id);
    
            Task<int>  GetUserId(string userName);
    
            Task<DateTime> GetUserLastSignInTime(int id);
    
            Task<UserModel> GetUser(int id);
    
            Task<bool> Update(int id, UserModel model);
    
            Task<IDictionary<string, string>> GetDictionary();
           
            Task TryThrowException();
        }
    

     创建领域对象

     UserModel:

       [ProtoContract]
        public class UserModel
        {
            [ProtoMember(1)]
            public string Name { get; set; }
    
            [ProtoMember(2)]
            public int Age { get; set; }
        }
    

     AssemblyInfo.cs,扩展AssemblyModuleType来标识模块,根据AssemblyModuleType进行相关规则的反射注册

    [assembly: AssemblyTitle("Surging.IModuleServices.Common")]
    [assembly: AssemblyDescription("业务模块接口")]
    [assembly: AssemblyModuleType(ModuleType.InterFaceService)]
    
    // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
    [assembly: Guid("2103624d-2bc2-4164-9aa5-1408daed9dee")]
    

    创建Domain Service

    PersonService.cs

    [ModuleName("Person")]  //标识实例化名称
        public class PersonService : ServiceBase,IUserService
        {
            #region Implementation of IUserService
            private readonly UserRepository _repository;
            public PersonService(UserRepository repository)
            {
                this._repository = repository;
            }
            
            public Task<string> GetUserName(int id)
            {
                return GetService<IUserService>("User").GetUserName(id);
            }
    
            public Task<bool> Exists(int id)
            {
                return Task.FromResult(true);
            }
    
            public Task<int> GetUserId(string userName)
            {
                return Task.FromResult(1);
            }
    
            public Task<DateTime> GetUserLastSignInTime(int id)
            {
                return Task.FromResult(DateTime.Now);
            }
    
            public Task<UserModel> GetUser(int id)
            {
                return Task.FromResult(new UserModel
                {
                    Name = "fanly",
                    Age = 18
                });
            }
    
            public Task<bool> Update(int id, UserModel model)
            {
                return Task.FromResult(true);
            }
    
            public Task<IDictionary<string, string>> GetDictionary()
            {
                return Task.FromResult<IDictionary<string, string>>(new Dictionary<string, string> { { "key", "value" } });
            }
    
            public async Task Try()
            {
                Console.WriteLine("start");
                await Task.Delay(5000);
                Console.WriteLine("end");
            }
    
            public Task TryThrowException()
            {
                throw new Exception("用户Id非法!");
            }
    
            #endregion Implementation of IUserService
        }
    }
    

     UserService.cs

    [ModuleName("User")]//标识实例化名称
       public class UserService: IUserService
        {
            #region Implementation of IUserService
            private readonly UserRepository _repository;
            public UserService(UserRepository repository)
            {
                this._repository = repository;
            }
    
            public Task<string> GetUserName(int id)
            {
                return Task.FromResult($"id:{id} is name fanly.");
            }
    
            public Task<bool> Exists(int id)
            {
                return Task.FromResult(true);
            }
    
            public Task<int> GetUserId(string userName)
            {
                return Task.FromResult(1);
            }
    
            public Task<DateTime> GetUserLastSignInTime(int id)
            {
                return Task.FromResult(DateTime.Now);
            }
    
            public Task<UserModel> GetUser(int id)
            {
                return Task.FromResult(new UserModel
                {
                    Name = "fanly",
                    Age = 18
                });
            }
    
            public Task<bool> Update(int id, UserModel model)
            {
                return Task.FromResult(true);
            }
    
            public Task<IDictionary<string, string>> GetDictionary()
            {
                return Task.FromResult<IDictionary<string, string>>(new Dictionary<string, string> { { "key", "value" } });
            }
    
            public async Task Try()
            {
                Console.WriteLine("start");
                await Task.Delay(5000);
                Console.WriteLine("end");
            }
    
            public Task TryThrowException()
            {
                throw new Exception("用户Id非法!");
            }
    
            #endregion Implementation of IUserService
        }
    }
    

    AssemblyInfo.cs,扩展AssemblyModuleType来标识模块,根据AssemblyModuleType进行相关规则的反射注册

    [ModuleName("User")]//标识实例化名称
       public class UserService: IUserService
        {
            #region Implementation of IUserService
            private readonly UserRepository _repository;
            public UserService(UserRepository repository)
            {
                this._repository = repository;
            }
    
            public Task<string> GetUserName(int id)
            {
                return Task.FromResult($"id:{id} is name fanly.");
            }
    
            public Task<bool> Exists(int id)
            {
                return Task.FromResult(true);
            }
    
            public Task<int> GetUserId(string userName)
            {
                return Task.FromResult(1);
            }
    
            public Task<DateTime> GetUserLastSignInTime(int id)
            {
                return Task.FromResult(DateTime.Now);
            }
    
            public Task<UserModel> GetUser(int id)
            {
                return Task.FromResult(new UserModel
                {
                    Name = "fanly",
                    Age = 18
                });
            }
    
            public Task<bool> Update(int id, UserModel model)
            {
                return Task.FromResult(true);
            }
    
            public Task<IDictionary<string, string>> GetDictionary()
            {
                return Task.FromResult<IDictionary<string, string>>(new Dictionary<string, string> { { "key", "value" } });
            }
    
            public async Task Try()
            {
                Console.WriteLine("start");
                await Task.Delay(5000);
                Console.WriteLine("end");
            }
    
            public Task TryThrowException()
            {
                throw new Exception("用户Id非法!");
            }
    
            #endregion Implementation of IUserService
        }
    }
    

    3.服务端

    using Autofac;
    using Autofac.Extensions.DependencyInjection;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Logging;
    using Surging.Core.Caching.Configurations;
    using Surging.Core.CPlatform;
    using Surging.Core.CPlatform.Runtime.Server;
    using Surging.Core.DotNetty;
    using Surging.Core.ProxyGenerator.Utilitys;
    using Surging.Core.System.Ioc;
    using Surging.Core.Zookeeper;
    using Surging.Core.Zookeeper.Configurations;
    using System;
    using System.Net;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Surging.Services.Server
    {
        public class Program
        {
            static void Main(string[] args)
            {
                Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
                var services = new ServiceCollection();
                var builder = new ContainerBuilder();
                ConfigureLogging(services);
                builder.Populate(services);
                ConfigureService(builder);
                ServiceLocator.Current = builder.Build();
                ConfigureCache();
                ServiceLocator.GetService<ILoggerFactory>()
                       .AddConsole((c, l) => (int)l >= 3);
                StartService();
                Console.ReadLine();
            }
    
            /// <summary>
            /// 配置相关服务
            /// </summary>
            /// <param name="builder"></param>
            /// <returns></returns>
            private static void ConfigureService(ContainerBuilder builder)
            {
                builder.Initialize();
                builder.RegisterServices();
                builder.RegisterRepositories();
                builder.RegisterModules();
                builder.AddCoreServce()
                     .AddServiceRuntime()
                     .UseSharedFileRouteManager("c:\routes.txt")//配置本地路由文件路径
                     .UseDotNettyTransport()//配置Netty
                    .UseZooKeeperRouteManager(new ConfigInfo("192.168.1.6:2181",
                        "/dotnet/unitTest/serviceRoutes"));//配置ZooKeeper
                builder.Register(p => new CPlatformContainer(ServiceLocator.Current));
            }
    
            /// <summary>
            /// 配置日志服务
            /// </summary>
            /// <param name="services"></param>
            public static void ConfigureLogging(IServiceCollection services)
            {
                services.AddLogging();
            }
    
            /// <summary>
            /// 配置缓存服务
            /// </summary>
            public static void ConfigureCache()
            {
                new ConfigurationBuilder()
               .SetBasePath(AppContext.BaseDirectory)
               .AddCacheFile("cacheSettings.json", optional: false);
            }
    
            /// <summary>
            /// 启动服务
            /// </summary>
            public static void StartService()
            {
                var serviceHost = ServiceLocator.GetService<IServiceHost>();
                Task.Factory.StartNew(async () =>
                {
                    await serviceHost.StartAsync(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 98));
                    Console.WriteLine($"服务端启动成功,{DateTime.Now}。");
                }).Wait();
            }
        }
    }
    

    4.客户端

    using Autofac;
    using Autofac.Extensions.DependencyInjection;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Logging;
    using Surging.Core.CPlatform;
    using Surging.Core.DotNetty;
    using Surging.Core.ProxyGenerator;
    using Surging.Core.ProxyGenerator.Utilitys;
    using Surging.Core.System.Ioc;
    using System.Text;
    
    namespace Surging.Services.Client
    {
        public class Program
        {
            static void Main(string[] args)
            {
                Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
                var services = new ServiceCollection();
                var builder = new ContainerBuilder();
                ConfigureLogging(services);
                builder.Populate(services);
                ConfigureService(builder);
                ServiceLocator.Current = builder.Build();
                ServiceLocator.GetService<ILoggerFactory>()
                    .AddConsole((c, l) => (int)l >= 3);
               
            }
    
            /// <summary>
            /// 配置相关服务
            /// </summary>
            /// <param name="builder"></param>
            /// <returns></returns>
            private static void ConfigureService(ContainerBuilder builder)
            {
                builder.Initialize();
                builder.RegisterServices();
                builder.RegisterRepositories();
                builder.RegisterModules();
                var serviceBulider = builder
                     .AddClient()
                     .UseSharedFileRouteManager("c:\routes.txt")
                     .UseDotNettyTransport();
            }
    
            /// <summary>
            /// 配置日志服务
            /// </summary>
            /// <param name="services"></param>
            public static void ConfigureLogging(IServiceCollection services)
            {
                services.AddLogging();
            }
    
            /// <summary>
            /// 配置服务代理
            /// </summary>
            /// <param name="builder"></param>
            /// <returns></returns>
            public static IServiceProxyFactory RegisterServiceProx(ContainerBuilder builder)
            {
                var serviceProxyFactory = ServiceLocator.GetService<IServiceProxyFactory>();
                serviceProxyFactory.RegisterProxType(builder.GetInterfaceService().ToArray());
                return serviceProxyFactory;
            }
            
        }
    }
    

    远程服务调用

    ServiceLocator.GetService<IServiceProxyFactory>().CreateProxy<T>(key)
    

    本地模块和服务调用

    ServiceLocator.GetService<T>(key)
    

    5.负载均衡

    surging提供3种负载均衡方式:

    Random:随机,调用量越大分布越均匀,默认是这种方式

    Polling:轮询,存在比较慢的机器容易在这台机器的请求阻塞较多

    HashAlgorithm:一致性哈希,对于相同参数的请求路由到一个服务提供者上。

    6.其他功能

    surging还会提供分布式缓存,AOP数据拦截,基于rabbitmq订阅发布, 监控服务,后续完善后再来讲解。

    6.性能测试

    测试环境

    CPU:Intel Core i7-4710MQ

    内存:16G

    硬盘:1T SSD+512G HDD

    网络:局域网

    测试结果如下:
    1万次调用,也就2290MS,平均单次也就0.229毫秒,性能不错。

    7.总结

    surging 0.0.0.1版本的发布意味着分布式微服务已经走出了第一步,以后还有很多工作需要完善。我会花很多空余时间去完善它。如果大家还有任何疑问或者感兴趣的话,可以加入QQ群:615562965
  • 相关阅读:
    组合与封装
    继承与派生
    面向对象编程
    subprocess、re、logging模块
    json、pickle、collections、openpyxl模块
    python内置模块
    递归函数与模块
    生成式、面向过程、与函数式
    叠加装饰器与迭代器
    闭包函数与装饰器
  • 原文地址:https://www.cnblogs.com/fanliang11/p/7049472.html
Copyright © 2011-2022 走看看