基於.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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM