自己动手,写一个分布式系统(附c#代码示例)
分布式系统有很多成熟的解决方案。如:微软的WCF。WCF太过于复杂,配置也麻烦。其实可以自己动手设计一个小的分布式系统。系统的原理完全在自己掌握之中,可以根据业务随机而变。这里展示远程调用最核心最基本的处理逻辑,其实远程调用并不复杂神秘。
分布式系统其实是数据流的交换。数据必须快速的从一段传送到另一端,否则系统性能就大打折扣。对于.net,本人设计一个非常优化易于使用的网络库(EasyNetMessage)。使用该库,不需要关心底层细节,所有处理对象是string、byte;发送时,不需要处理分包(几十M的数据也可以一次发送);收包时,不需要处理粘包。本文所示例代码,就是基于该网络库。本文章实例代码见底部。
实现目标
实现一个非常简单的应用 internal int AddCall(int value1, int value2);就是两个整数相加。调用过程和本地完全一样,只是执行加法操作是在远程服务器实现的。操作非常简单,但是揭示了远程调用的核心处理流程。
处理过程:
a) 数据发送
每次函数调用必须有一个唯一标识CallId,这个也是发包的唯一标识;服务端处理完后,返回的结果也带有此标识。通过此标识,将发送端数据和返回数据关联起来了。
发送完数据后,客户端线程要挂起,等待服务器端的处理结果。线程挂起使用ManualResetEvent。并建立起CallId与ManualResetEvent的对应关系。当数据返回时,就能找到对应的ManualResetEvent。
//callid与事件关联
Dictionary<int, ManualResetEvent> _callEventGroup = new Dictionary<int, ManualResetEvent>();
//callId与返回结果关联
Dictionary<int, NetCallAddAck> _callResultGroup = new Dictionary<int, NetCallAddAck>();
internal int AddCall(int value1, int value2)
{
//组织发送包
NetCallAdd add = new NetCallAdd();
add.Value1 = value1.ToString();
add.Value2 = value2.ToString(); MonitorClient client = GetCurAppClient();
if (client == null)
throw new Exception("socket未连接!"); //生成线程事件,并与CallId关联
ManualResetEvent callEvent = new ManualResetEvent(false);
lock (_callEventGroup)
{
_callEventGroup.Add(add.CallId, callEvent);
} //发送数据
EN_SendDataResult result = _netServer.SendData(client.ClientSocket, add.ToEasyMessage().ToNetPacket());
if (result != EN_SendDataResult.ok)
{
lock (_callEventGroup)
{
_callEventGroup.Remove(add.CallId);
}
throw new Exception("网络发送异常!");
} //等待结果
callEvent.WaitOne();
_callEventGroup.Remove(add.CallId); //查看结果集
lock (_callResultGroup)
{
if (_callResultGroup.ContainsKey(add.CallId))
{
NetCallAddAck ack = _callResultGroup[add.CallId];
return int.Parse(ack.Result);
}
} throw new Exception("没有返回结果!");
}
b)数据返回
数据返回后的处理是在另一个线程。数据返回后,先根据CallId查找对应的ManualResetEvent;如果找不到,有可能服务器处理太慢,超时了。
先将返回结果存储到哈希数组中,key为CallId。再调用ManualResetEvent的Set函数,唤醒调用端线程。调用端线程根据CallId到哈希表中获取结果。
internal void OnRcvAck(NetCallAddAck addAck)
{
//根据callid找到事件
ManualResetEvent callEvent = null;
lock (_callEventGroup)
{
if (!_callEventGroup.ContainsKey(addAck.CallId))
return;
callEvent =_callEventGroup[addAck.CallId];
} //结果存放到哈希表中
lock (_callResultGroup)
{
_callResultGroup.Remove(addAck.CallId);
_callResultGroup.Add(addAck.CallId, addAck);
}
//设置事件为有信号,调用方挂起的线程可以继续执行
callEvent.Set();
}
进一步说明:可以在此基础上,进一步扩展。开发出类似Redis的内存库。客户端的调用也不一定是同步 ,可以采用异步回调的方式处理。其实如果知道处理的原理,可以根据自己的业务做裁剪。只有知其所以然,才能开发出最符合自己业务的系统,才可能进一步优化。
实例代码https://download.csdn.net/download/qq_29939347/10684858
自己动手,写一个分布式系统(附c#代码示例)的更多相关文章
- 动手写一个简单版的谷歌TPU-矩阵乘法和卷积
谷歌TPU是一个设计良好的矩阵计算加速单元,可以很好的加速神经网络的计算.本系列文章将利用公开的TPU V1相关资料,对其进行一定的简化.推测和修改,来实际编写一个简单版本的谷歌TPU.计划实现到行为 ...
- 死磕 java同步系列之自己动手写一个锁Lock
问题 (1)自己动手写一个锁需要哪些知识? (2)自己动手写一个锁到底有多简单? (3)自己能不能写出来一个完美的锁? 简介 本篇文章的目标一是自己动手写一个锁,这个锁的功能很简单,能进行正常的加锁. ...
- 动手写一个简单版的谷歌TPU-指令集
系列目录 谷歌TPU概述和简化 基本单元-矩阵乘法阵列 基本单元-归一化和池化(待发布) TPU中的指令集 SimpleTPU实例: (计划中) 拓展 TPU的边界(规划中) 重新审视深度神经网络中的 ...
- 死磕 java线程系列之自己动手写一个线程池
欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. (手机横屏看源码更方便) 问题 (1)自己动手写一个线程池需要考虑哪些因素? (2)自己动手写 ...
- 自己动手写一个服务网关-java
自己动手写一个服务网关 原文链接:https://www.cnblogs.com/bigben0123/p/9252444.html 引言 什么是网关?为什么需要使用网关? 如图所示,在不使用网关的情 ...
- 动手写一个简单的Web框架(模板渲染)
动手写一个简单的Web框架(模板渲染) 在百度上搜索jinja2,显示的大部分内容都是jinja2的渲染语法,这个不是Web框架需要做的事,最终,居然在Werkzeug的官方文档里找到模板渲染的代码. ...
- 动手写一个简单的Web框架(Werkzeug路由问题)
动手写一个简单的Web框架(Werkzeug路由问题) 继承上一篇博客,实现了HelloWorld,但是这并不是一个Web框架,只是自己手写的一个程序,别人是无法通过自己定义路由和返回文本,来使用的, ...
- 动手写一个简单的Web框架(HelloWorld的实现)
动手写一个简单的Web框架(HelloWorld的实现) 关于python的wsgi问题可以看这篇博客 我就不具体阐述了,简单来说,wsgi标准需要我们提供一个可以被调用的python程序,可以实函数 ...
- 使用gfortran将数据写成Grads格式的代码示例
使用gfortran将数据写成Grads格式的代码示例: !-----'Fortran4Grads.f90' program Fortran4Grads implicit none integer,p ...
随机推荐
- abp Cannot access a disposed object. A common cause of this error is disposing
框架:abp 异常信息: An unhandled exception was thrown by the application.System.ObjectDisposedException: Ca ...
- Ubuntu部署可视化爬虫Portia2.0环境以及入门
http://www.cnblogs.com/kfpa/p/Portia.html http://brucedone.com/archives/986
- C# Form Chart X刻度左右多余一格怎么去掉
如上图所示:形成的chart,1和8时y没有值,我实际给的也是2~7的数,可视1和8的刻度却在,怎么去掉,谢谢. 解决方法:chart1.ChartAreas[0].AxisX.IsMarginVis ...
- 第二次spring会议
今天所做之事: 我用C#用DelectText对行数进行了定义,刚开始写代码有点无从下手. 遇到的问题:刚开始用datagridView进行了文本的输入,但是它更适合EXCEL之类的数据计算不符合我们 ...
- Alpha 冲刺 (10/10)
队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭鸭鸭鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 测试整体软件 展示GitHub当 ...
- CDH版本的hadoop下载
http://archive.cloudera.com/cdh5/cdh/5/加要下载的cdh版本插件 例如: http://archive.cloudera.com/cdh5/cdh/5/zooke ...
- Linux 网卡Bond模式
网卡bond是通过把多张网卡绑定为一个逻辑网卡,实现本地网卡的冗余,带宽扩容和负载均衡. 有7种模式: mod 0/mod 1/mod 2/mod 3/mod 4/mod 5 mod=0 ,即:(ba ...
- 综合数据api接口使用
由于请求数据接口是跨域的,但是我们无法改变接口的代码 先从请求后台,然后从后台进行二次请求,请求数据接口 原生代码 package edu.nf.http.test; import org.apach ...
- 【转】Closeable, Readable, Flushable, Appendable
Closeable: package java.io; import java.io.IOException; public interface Closeable { /** * Closes th ...
- 学以致用二十八-----win10安装mysql5.7.24及卸载
1.在windows环境下安装mysql,需要下载相对应的版本. ------------------------> 这里我下载的是mysql-5.7.24-win64.zip 2.下载后解压, ...