surging 集成SuperSocket预发布版本2.0
一、概述
周末在家试着扩展SuperSocket,因为之前都是只支持.net framework, 后面出现支持.NET CORE 的SuperSocket 2.0 ,然后集成进来和dotnetty 做下对比,dotnetty 有多强,我压测可以支持20w/s, 然后客户提供的服务器,通过外网压测网关,把上行速度50MB带宽的网络跑满了,引擎主机CPU只是在15%左右,完全没有跑满。然后再试试国人开发的SuperSocket看下性能怎么样。
木舟 (Kayak) 是什么?
木舟(Kayak)是基于.NET6.0软件环境下的surging微服务引擎进行开发的, 平台包含了微服务和物联网平台。支持异步和响应式编程开发,功能包含了物模型,设备,产品,网络组件的统一管理和微服务平台下的注册中心,服务路由,模块,中间服务等管理。还有多协议适配(TCP,MQTT,UDP,CoAP,HTTP,Grpc,websocket,rtmp,httpflv,webservice,等),通过灵活多样的配置适配能够接入不同厂家不同协议等设备。并且通过设备告警,消息通知,数据可视化等功能。能够让你能快速建立起微服务物联网平台系统。
凯亚物联网平台:http://117.72.121.2:3100(用户名:fanly 密码:123456)(木舟物联网有人取了,准备改名原神凯亚,凡是交托于他的任务,总能得到解决)
链路跟踪Skywalking V8:http://117.72.121.2:8080/
surging 微服务引擎开源地址:https://github.com/fanliang11/surging(后面surging 会移动到microsurging进行维护)
二、集成SuperSocket
作为去中心化的微服务引擎,相关的引擎组件,中间件都可以替换,就比如核心的RPC组件dotnetty 都可以替换成其它组件,下面介绍如何进行替换
创建服务端消息监听SuperSocketServerMessageListener,需要继承IMessageListener,代码如下:
public class SuperSocketServerMessageListener : IMessageListener, IDisposable
{
public event ReceivedDelegate Received; private readonly ILogger<SuperSocketServerMessageListener> _logger; private readonly ITransportMessageDecoder _transportMessageDecoder;
private readonly ITransportMessageEncoder _transportMessageEncoder;
private readonly IServiceEngineLifetime _serviceEngineLifetime; public SuperSocketServerMessageListener(ILogger<SuperSocketServerMessageListener> logger, ITransportMessageCodecFactory codecFactory, IServiceEngineLifetime serviceEngineLifetime)
{
_logger = logger;
_transportMessageEncoder = codecFactory.GetEncoder();
_transportMessageDecoder = codecFactory.GetDecoder();
_serviceEngineLifetime = serviceEngineLifetime;
}
public async Task StartAsync(EndPoint endPoint)
{ _serviceEngineLifetime.ServiceEngineStarted.Register(async () =>
{
try
{
var ipEndPoint = endPoint as IPEndPoint;
var host = SuperSocketHostBuilder.Create<TransportMessage, TransportMessagePipelineFilter>() .UsePackageHandler( (s, p) =>
{
Task.Run(async () =>
{
var sender = new SuperSocketServerMessageSender(_transportMessageEncoder, s);
await OnReceived(sender, p);
});
return ValueTask.CompletedTask;
})
.ConfigureSuperSocket(options =>
{
options.Name = "Echo Server";
options.Logger = _logger;
options.AddListener(new ListenOptions
{
Ip = ipEndPoint.Address.ToString(),
Port = ipEndPoint.Port, }
);
})
.ConfigureLogging((hostCtx, loggingBuilder) =>
{
loggingBuilder.AddConsole();
})
.Build();
await host.RunAsync();
}
catch (Exception ex)
{
_logger.LogError($"SuperSocket服务主机启动失败,监听地址:{endPoint}。 ");
}
}); } public async Task OnReceived(IMessageSender sender, TransportMessage message)
{
if (Received == null)
return;
await Received(sender, message);
} public void Dispose()
{
}
}
创建客户端消息监听SuperSocketTransportClientFactory,需要继承ITransportClientFactory,代码如下:
internal class SuperSocketTransportClientFactory : ITransportClientFactory, IDisposable
{
private readonly ITransportMessageEncoder _transportMessageEncoder;
private readonly ITransportMessageDecoder _transportMessageDecoder;
private readonly ILogger<SuperSocketTransportClientFactory> _logger;
private readonly IServiceExecutor _serviceExecutor;
private readonly IHealthCheckService _healthCheckService;
private readonly ConcurrentDictionary<EndPoint, Lazy<Task<ITransportClient>>> _clients = new ConcurrentDictionary<EndPoint, Lazy<Task<ITransportClient>>>(); public SuperSocketTransportClientFactory(ITransportMessageCodecFactory codecFactory, IHealthCheckService healthCheckService, ILogger<SuperSocketTransportClientFactory> logger)
: this(codecFactory, healthCheckService, logger, null)
{
} public SuperSocketTransportClientFactory(ITransportMessageCodecFactory codecFactory, IHealthCheckService healthCheckService, ILogger<SuperSocketTransportClientFactory> logger, IServiceExecutor serviceExecutor)
{
_transportMessageEncoder = codecFactory.GetEncoder();
_transportMessageDecoder = codecFactory.GetDecoder();
_logger = logger;
_serviceExecutor = serviceExecutor;
_healthCheckService = healthCheckService;
}
public async Task<ITransportClient> CreateClientAsync(EndPoint endPoint)
{
var key = endPoint;
if (_logger.IsEnabled(LogLevel.Debug))
_logger.LogDebug($"准备为服务端地址:{key}创建客户端。");
try
{
return await _clients.GetOrAdd(key
, k => new Lazy<Task<ITransportClient>>(async () =>
{
//客户端对象
var client = new EasyClient<TransportMessage>(new TransportMessagePipelineFilter()).AsClient();
var messageListener = new MessageListener();
var messageSender = new SuperSocketMessageClientSender(_transportMessageEncoder, client);
await client.ConnectAsync(endPoint);
client.PackageHandler += async (sender, package) =>
{
await messageListener.OnReceived(messageSender, package);
};
client.StartReceive();
//创建客户端
var transportClient = new TransportClient(messageSender, messageListener, _logger, _serviceExecutor);
return transportClient;
}
)).Value;//返回实例
}
catch
{
//移除
_clients.TryRemove(key, out var value);
var ipEndPoint = endPoint as IPEndPoint;
//标记这个地址是失败的请求
if (ipEndPoint != null)
await _healthCheckService.MarkFailure(new IpAddressModel(ipEndPoint.Address.ToString(), ipEndPoint.Port));
throw;
}
} public void Dispose()
{
foreach (var client in _clients.Values)
{
(client as IDisposable)?.Dispose();
}
}
}
注册初始化SuperSocket引擎模块,需要继承EnginePartModule, 代码如下:
public class SuperSocketModule : EnginePartModule
{
public override void Initialize(AppModuleContext context)
{
base.Initialize(context);
} /// <summary>
/// Inject dependent third-party components
/// </summary>
/// <param name="builder"></param>
protected override void RegisterBuilder(ContainerBuilderWrapper builder)
{
base.RegisterBuilder(builder);
builder.Register(provider =>
{
IServiceExecutor serviceExecutor = null;
if (provider.IsRegistered(typeof(IServiceExecutor)))
serviceExecutor = provider.Resolve<IServiceExecutor>();
return new SuperSocketTransportClientFactory(provider.Resolve<ITransportMessageCodecFactory>(),
provider.Resolve<IHealthCheckService>(),
provider.Resolve<ILogger<SuperSocketTransportClientFactory>>(),
serviceExecutor);
}).As(typeof(ITransportClientFactory)).SingleInstance();
if (AppConfig.ServerOptions.Protocol == CommunicationProtocol.Tcp ||
AppConfig.ServerOptions.Protocol == CommunicationProtocol.None)
{
RegisterDefaultProtocol(builder);
}
} private void RegisterDefaultProtocol(ContainerBuilderWrapper builder)
{
builder.Register(provider =>
{
return new SuperSocketServerMessageListener(provider.Resolve<ILogger<SuperSocketServerMessageListener>>(),
provider.Resolve<ITransportMessageCodecFactory>(),
provider.Resolve<IServiceEngineLifetime>());
}).SingleInstance();
builder.Register(provider =>
{
var serviceExecutor = provider.ResolveKeyed<IServiceExecutor>(CommunicationProtocol.Tcp.ToString());
var messageListener = provider.Resolve<SuperSocketServerMessageListener>();
return new DefaultServiceHost(async endPoint =>
{
await messageListener.StartAsync(endPoint);
return messageListener;
}, serviceExecutor);
}).As<IServiceHost>();
}
}
客户端服务端消息发送,需要继承IMessageSender, 代码如下:
public abstract class SuperSocketMessageSender
{
private readonly ITransportMessageEncoder _transportMessageEncoder; protected SuperSocketMessageSender(ITransportMessageEncoder transportMessageEncoder)
{
_transportMessageEncoder = transportMessageEncoder;
} protected byte[] GetByteBuffer(TransportMessage message)
{
var data = _transportMessageEncoder.Encode(message).ToList();
data.AddRange(Encoding.UTF8.GetBytes("\r\n"));
//var buffer = PooledByteBufferAllocator.Default.Buffer();
return data.ToArray();
}
} public class SuperSocketMessageClientSender : SuperSocketMessageSender, IMessageSender
{
private readonly IEasyClient<TransportMessage> _client; public SuperSocketMessageClientSender(ITransportMessageEncoder transportMessageEncoder, IEasyClient<TransportMessage> client) : base(transportMessageEncoder)
{
_client = client;
} /// <summary>
/// 发送消息。
/// </summary>
/// <param name="message">消息内容。</param>
/// <returns>一个任务。</returns>
public async Task SendAsync(TransportMessage message)
{
var buffer = GetByteBuffer(message);
await _client.SendAsync(buffer);
} /// <summary>
/// 发送消息并清空缓冲区。
/// </summary>
/// <param name="message">消息内容。</param>
/// <returns>一个任务。</returns>
public async Task SendAndFlushAsync(TransportMessage message)
{
var buffer = GetByteBuffer(message);
await _client.SendAsync(buffer);
// _client.StartReceive();
//var p= await _client.ReceiveAsync();
}
} #region Implementation of IMessageSender
public class SuperSocketServerMessageSender : SuperSocketMessageSender, IMessageSender
{
private readonly IAppSession _session; public SuperSocketServerMessageSender(ITransportMessageEncoder transportMessageEncoder, IAppSession session) : base(transportMessageEncoder)
{
_session = session;
} /// <summary>
/// 发送消息。
/// </summary>
/// <param name="message">消息内容。</param>
/// <returns>一个任务。</returns>
public async Task SendAsync(TransportMessage message)
{
var buffer = GetByteBuffer(message);
await _session.SendAsync(buffer);
} /// <summary>
/// 发送消息并清空缓冲区。
/// </summary>
/// <param name="message">消息内容。</param>
/// <returns>一个任务。</returns>
public async Task SendAndFlushAsync(TransportMessage message)
{
var buffer = GetByteBuffer(message);
await _session.SendAsync(buffer);
} }
#endregion
SuperSocket过滤器,需要继承TerminatorPipelineFilter<TransportMessage>, 代码如下:
public class TransportMessagePipelineFilter : TerminatorPipelineFilter<TransportMessage>
{
private readonly ITransportMessageDecoder _transportMessageDecoder;
public TransportMessagePipelineFilter() : base(new[] { (byte)'\r', (byte)'\n' })
{
_transportMessageDecoder = ServiceLocator.GetService<ITransportMessageCodecFactory>().GetDecoder();
} public override TransportMessage Filter(ref SequenceReader<byte> bufferStream)
{
try
{
var bytes = bufferStream.Sequence.Slice(0, bufferStream.Length - 2).ToArray();
var transportMessage = _transportMessageDecoder.Decode(bytes);
return transportMessage;
}
finally
{
bufferStream.Advance(bufferStream.Length);
}
}
}
三、如何加载SuperSocket引擎组件
第一种方式:
去掉Surging.Core.DotNetty引用,添加Surging.Core.SuperSocket
第二种方式
添加Surging.Core.DotNetty,Surging.Core.SuperSocket这两个应用,在surgingSettings.json配置文件中把Packages的using列表中的DotNettyModule改成SuperSocketModule
四、结果
可能是预发布版本,在测试当中还是有些问题,kayka物联网平台换成SuperSocket还是会发生错误,暂时没有条件进行压测,可能是因为预发布版本,作者还需要完善,等正式版之后再压测做对比吧
五、总结
因为这段时间比较忙,还需要协助客户拆分服务,缓存降级,消息队列,等忙完这段时间,线上物联网平台会开通端口给用户进行测试,我也会努力把物联网进行完善,让微服务物联网平台能走向新的高度。
surging 集成SuperSocket预发布版本2.0的更多相关文章
- 重要消息:MoviePy v2.0.0.dev1预发布版本已经可以下载安装使用
☞ ░ 前往老猿Python博文目录 ░ 刚刚得知,MoviePy v2.0.0.dev1版本已经预发布,据说解决了多语言支持及TextClip等一系列Bug,大家不妨升级使用.升级指令:pip in ...
- 驰骋工作流引擎与jFinal集成版本2.0
驰骋工作流引擎与jFinal集成版本2.0 发布说明 关键字: 驰骋工作流程快速开发平台 工作流程管理系统java工作流引擎. 使用协议:GPL. 关于JFinal: https://www.jfin ...
- InstallShield集成安装MSDE2000最小版本(二) fishout特许授权发布
原文:InstallShield集成安装MSDE2000最小版本(二) fishout特许授权发布 原帖地址:http://blog.csdn.net/fishout/archive/2009/10/ ...
- InstallShield集成安装MSDE2000最小版本(三) fishout特许授权发布
原文:InstallShield集成安装MSDE2000最小版本(三) fishout特许授权发布 原帖地址:http://blog.csdn.net/fishout/archive/2009/11/ ...
- InstallShield集成安装MSDE2000最小版本(一) fishout特许授权发布
原文:InstallShield集成安装MSDE2000最小版本(一) fishout特许授权发布 原帖地址:http://blog.csdn.net/fishout/archive/2009/10/ ...
- 发行说明 - Kafka - 版本1.0.0
发行说明 - Kafka - 版本1.0.0 以下是Kafka 1.0.0发行版中解决的JIRA问题的摘要.有关该版本的完整文档,入门指南以及有关该项目的信息,请参阅Kafka项目网站. 有关升级的注 ...
- 历时2月,动态线程池 DynamicTp 发布里程碑版本 V1.0.8
关于 DynamicTp DynamicTp 是一个基于配置中心实现的轻量级动态线程池管理工具,主要功能可以总结为动态调参.通知报警.运行监控.三方包线程池管理等几大类. 经过多个版本迭代,目前最新版 ...
- C# 语言规范_版本5.0 (第0章 目录)
C# 语言规范 版本5.0 注意 © 1999-2012 Microsoft Corporation.保留所有权利. Microsoft.Windows.Visual Basic.Visual C# ...
- 关于Visio Studio 2012使用Nuget获取Sqlite驱动包报错:“System.Data.SQLite.EF6”的架构版本与 NuGet 的版本 2.0.30625.9003 不兼容
背景 笔者的VS2012版本比较老旧,是几年以前下载的.平时添加三方包和驱动包都是手动添加.后来了解到有Nuget这个工具,如获至宝.可是在使用过程中却出了不少问题. 最初,笔者尝试使用Nuget添加 ...
- jenkins 实现测试发布、预发布、真实发布、回滚发布
主要思路: 1.做三个文件夹,用于放置不可随意修改的配置文件(测试发布.预发布.真实发布) 2.每次都先修改配置文件再进行构建(构建时会先把配置文件复制到构建的目录,再同步到发布的目录) 3.发布完代 ...
随机推荐
- 多方安全计算(3):MPC万能钥匙-混淆电路
学习&转载文章:多方安全计算(3):MPC万能钥匙-混淆电路 前言 我们在讲解不经意传输(Oblivious Transfer,OT)的文章(安全多方计算(1):不经意传输协议)中提到,利用n ...
- Rookie Mistake pg walkthrough Intermediate jwt+ssti
nmap ┌──(root㉿kali)-[~/lab] └─# nmap -p- -A 192.168.189.221 Starting Nmap 7.94SVN ( https://nmap.org ...
- LeetCode刷题:runtime error: reference binding to null pointer of type 'int' (stl_vector.h)报错请教
题目:https://leetcode.cn/problems/merge-intervals/ 错误代码: // 思路初探:做了很多道类似区间操作的题目了.本题就是尽可能少的创建新区间 // 1.首 ...
- Markdown语法基础教学
Markdown语法基础教学 简介 Markdown是一种轻量级的标记语言,它允许人们使用易读易写的纯文本格式编写文档,然后转换成结构化的HTML.它的目标是实现"易读易写",并且 ...
- 【Unity】URP中的UGUIShader实现
[Unity]URP 中的 UGUIShader 实现 参考官方 Shader 代码实现: https://github.com/TwoTailsGames/Unity-Built-in-Shader ...
- ReviOS - 专为游戏优化的 Win11 / Win10 精简版系统
ReviOS介绍 ReviOS 渴望重新创建作为操作系统的 Windows 应该是 - 简单.ReviOS 是一款功能强大.高效的私有操作系统,适用于游戏玩家.高级用户和发烧友.由于资源.占用内存和存 ...
- 洛谷P11380 [GESP202412 八级] 排队 题解
数据太可恶了,竟然有重边!!! 题目传送门. 显然一道简单图论题. 把 \(a_i\) 和 \(b_i\) 的关系想象成一条有向边,于是可以得出:如果 \(x\) 的出度大于 \(1\) 或者 \(x ...
- Java字节码增强实际应用在哪些方面?
Java字节码增强由于与业务应用耦合性较低,且可任意修改程序代码,所以在许多方面都有应用.也是许多公司产品实现的基础.下面大概分类一下: 1.在可观测和监控方面的应用 如果一个应用的架构服务之间的依赖 ...
- LaTeX使用记录
安装与使用 曾在Windows10下装过MikTeX,并配合vscode插件LaTeX Workshop使用过一段时间:这次转到wsl2中,并使用texlive,所以插件的配置json需要小修改 参考 ...
- css 技巧:利用 after 伪对象和 background 属性实现 img 图片标签占位图
同步发布:https://blog.jijian.link/2020-04-15/css-img-after-placeholder/ 如图: 图片加载失败了,在浏览器会默认显示一张破图.受各种网速. ...