XRPC的目標非常明確,就是給.net core平台實現一個百萬級別的遠程方法調用RPC通訊組件。它的設計理念和GRPC一樣,基於連接復用的機制實現高吞的性能;XRPC采用了HTTP2復用的思想,在協議設計上也類似文本和二進制相結合;在應用層面並沒使用消息而是基於接口代理的方式讓使用更簡便。
協議序列化
XRPC采用了基於文本+二進制相結合的通訊協議,頭以文本的方式表現主要是描述請求的位置和附加信息,這樣設計的好處就是在實現網關的時候只需要解釋頭部就能做很好的負載策略。二進制處理並沒有像GPRC一樣使 Protobuf,而是使用了在.net core平台下相對更高效的組件MessagePack。
通訊機制
在早期很多RPC是基於獨享連和連接池的方式進行構建,這樣的好處就是實現起來方便簡單,但這種設計就無法把不同請求的請求混合到一個IO上。導致網絡IO隨並發消息的增長而增長,從而局限了性能的發揮。XRPC的設計是盡量在最少連接情況發揮更高效的網絡處理能力,這樣就可以把N個請求的數據復用在一個IO上,而從讓網絡利用率大大提升。

但這種設計的缺點就是使用起來非常復雜,不過在.NET提供async/await支持下整體設計和應用就變得相對簡單和清晰很多了。現在模塊已經完成基礎功能版本,以下介紹一下如何使用。
組件使用
組件現在只完成最基礎的功能,后面會引用Actor的一些基礎元素,讓在並發業務處理數據上更高效。可以通過Nuget引用組件
Install-Package BeetleX.XRPC -Version x
定義接口服務
XRPC是通過接口的方式來描述服務,通過接口制定相關服務的邏輯,具體實現如下:
[Controller(typeof(IUserService))]
public class UserService : IUserService
{
public Task<User> Add(string name, string email, string city, string remark)
{
User user = new User();
user.Name = name;
user.EMail = email;
user.City = city;
user.Remark = remark;
return Task.FromResult(user);
}
public Task<List<User>> List(int count)
{
List<User> result = new List<User>();
for (int i = 0; i < count; i++)
{
User user = new User();
user.ID = Guid.NewGuid().ToString("N");
user.City = "GuangZhou";
user.EMail = "Henryfan@msn.com";
user.Name = "henryfan";
user.Remark = "http://ikende.com";
result.Add(user);
}
return Task.FromResult(result);
}
public bool Login(string name, string pwd)
{
return (name == "admin" && pwd == "123456");
}
public User Modify(User user)
{
return user;
}
public void Save()
{
Console.WriteLine("user saved");
}
}
啟動服務
class Program
{
private static XRPCServer mXRPCServer;
static void Main(string[] args)
{
mXRPCServer = new XRPCServer();
//mXRPCServer.ServerOptions.DefaultListen.Port = 80;
mXRPCServer.Register(typeof(Program).Assembly);
mXRPCServer.Open();
Console.Read();
}
}
通過Register注冊相關程序集,組件會把程序集中所有控制器加載到內存中,可以通過日志加載情況:

Client定義
client = new XRPCClient("localhost", 9090);
client.Connect();
client.NetError = (c, e) =>
{
Console.WriteLine(e.Error.Message);
};
client.TimeOut = 10000;
定義一個XRPCClient對象來進行遠程訪問,對象默認最大連接數是2,也可以根據自己實情況進行調整,不建增加這樣會導致網絡IO也會增加影響整體性能。
var api = client.Create<IUserService>();
var lresult = await api.Login("admin", "123456");
Console.WriteLine(lresult);
var result = await api.Add("henry", "henryfan@msn.com", "gz", "http://github.com");
Console.WriteLine($"{result.Name}\t{result.EMail}\t{result.City}\t{result.Remark}");
await api.Save();
Console.WriteLine("save completed");
User user = new User();
user.ID = Guid.NewGuid().ToString("N");
user.Name = "henry";
user.EMail = "henryfan@msn.com";
user.City = "GuangZhou";
user.Remark = "http://github.com/ikende";
result = await api.Modify(user);
Console.WriteLine($"{result.Name}\t{result.EMail}\t{result.City}\t{result.Remark}");
var items = await api.List(5);
foreach(var item in items)
{
Console.WriteLine($"{item.Name}\t{item.EMail}\t{item.City}\t{item.Remark}");
}
通過Create方法可以創建接口代理,這個代理是線程安全的,正常情況只需要創建一個靜態成員即可;創建接口后只需要調用相關方法即可完成遠程方法的調用。
基礎性能
組件設計的性能目標是百萬級別RPS的遠程方法調用,不過在一台4核物機作為服務測試並沒有達到這個目標,不過測試結果還算比較理想,在以上示例代碼Login方法,采用500個並發模擬的情況RPS達到將近70萬。以下是不同方法在不同並發數下的測試結果。

詳細測試代碼:https://github.com/IKende/XRPC/tree/master/Samples/Performance
