一、前言
至今为止编程开发已经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 能成为i最流行的技术。
surging从技术层面来说就是基于RPC协议的分布式微服务技术框架,框架依赖于Netty 进行异步通信,采用Zookeeper作为服务注册中心,集成了哈希,随机和轮询作为负载均衡算法
1.服务化应用基本框架
框架的执行过程如下:
1.服务提供者启动,根据RPC协议通过配置的IP和port绑定到netty上
2.注册服务信息存储至Zookeeper
3.客户端CreateProxy调用服务时,从内存中拿到上次通知的所有效的服务地址,根据路由信息和负载均衡机制选择最终调用的服务地址,发起调用
2.简单示例
创建IModuleServices
IUserService.cs:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
[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:
1
2
3
4
5
6
7
8
9
|
[ProtoContract]
public
class
UserModel
{
[ProtoMember(1)]
public
string
Name {
get
;
set
; }
[ProtoMember(2)]
public
int
Age {
get
;
set
; }
}
|
AssemblyInfo.cs,扩展AssemblyModuleType来标识模块,根据AssemblyModuleType进行相关规则的反射注册
1
2
3
4
5
6
|
[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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
[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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
[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进行相关规则的反射注册
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
[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.服务端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
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.客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
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;
}
}
}
|
远程服务调用
1
|
ServiceLocator.GetService<IServiceProxyFactory>().CreateProxy<T>(key)
|
本地模块和服务调用
1
|
ServiceLocator.GetService<IServiceProxyFactory>().CreateProxy<T>(key)
|
5.负载均衡
surging提供3种负载均衡方式:
Random:随机,调用量越大分布越均匀,默认是这种方式
Polling:轮询,存在比较慢的机器容易在这台机器的请求阻塞较多
HashAlgorithm:一致性哈希,对于相同参数的请求路由到一个服务提供者上。
6.其他功能
surging还会提供分布式缓存,AOP数据拦截,基于rabbitmq订阅发布, 监控服务,后续完善后再来讲解。
6.性能测试
测试环境
CPU:Intel Core i7-4710MQ
内存:16G
硬盘:1T SSD+512G HDD
网络:局域网
7.总结
surging 0.0.0.1版本的发布意味着分布式微服务已经走出了第一步,以后还有很多工作需要完善。我会花很多空余时间去完善它。