C#手动做一个负载均衡服务器
思路
负载均衡服务器最出名的当数 Nginx了。Nginx服务器通过异步的方式把连接转发给内网和N个服务器,用来分解单台应用服务器的压力,了解了原理及场景后,用C#来实现一个。思路如下:
1. 使用一个站点的 Application_BeginRequest 来接收连接,转发连接。
2. 对各类静态资源做单独处理,(可转可不转)
3. 可以转发Get,Post,异步转发。
4. 对指定的请求,转发到同一台服务器,保持使用者的登录状态。
实现
Vs2015建一个Mvc建站: localhost:1500/。修改Web.config,用于接收所有连接。
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
</modules>
</system.webServer>
引入 MyCmn.dll (http://code.taobao.org/svn/MyOql/libs4/),MyHelper 封装了 类型转换函数,方便使用。
代码如下:
(项目Svn地址: http://code.taobao.org/svn/MyMvcApp/MyProxy)
public class RequestWrap
{
public HttpWebRequest Request { get; set; }
private ManualResetEvent Event { get; set; }
private Action<HttpWebResponse> Action { get; set; }
public RequestWrap(HttpWebRequest request)
{
Event = new ManualResetEvent(false);
this.Request = request;
} public void Run(Action<HttpWebResponse> act)
{
this.Action = act; Request.BeginGetResponse(new AsyncCallback(GetResponseCallback), this);
this.Event.WaitOne();
} private static void GetResponseCallback(IAsyncResult asyncResult)
{
RequestWrap wrap = (RequestWrap)asyncResult.AsyncState;
HttpWebResponse response = null;
try
{
response = wrap.Request.EndGetResponse(asyncResult) as HttpWebResponse;
}
catch (WebException ex)
{
response = ex.Response as HttpWebResponse;
}
wrap.Action(response);
wrap.Event.Set();
}
} private void Application_BeginRequest(Object source, EventArgs e)
{
var lastExtName = "";
{
var lastIndex = Request.Url.LocalPath.LastIndexOf('.');
if (lastIndex > )
{
lastExtName = Request.Url.LocalPath.Slice(lastIndex);
}
} // <modules runAllManagedModulesForAllRequests="true"> 设置之后,静态资源就进来了。
if (lastExtName.IsIn(".js", ".css", ".html", ".htm", ".png", ".jpg", ".gif"))
{
return;
} HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(GetTransferHost() + Request.RawUrl);
myRequest.Proxy = null; myRequest.Timeout = ;
myRequest.ReadWriteTimeout = ; myRequest.Method = Request.HttpMethod; Request.Headers.AllKeys.All(k =>
{
if (!WebHeaderCollection.IsRestricted(k))
{
myRequest.Headers.Add(k, Request.Headers[k]);
}
else
{
var val = Request.Headers[k];
if (k.Is("Range"))
{
myRequest.AddRange(val.AsInt());
}
else if (k.Is("If-Modified-Since"))
{
myRequest.IfModifiedSince = val.AsDateTime();
}
else if (k.Is("Accept"))
{
myRequest.Accept = val;
}
else if (k.Is("Content-Type"))
{
myRequest.ContentType = val;
}
else if (k.Is("Expect"))
{
myRequest.Expect = val;
}
else if (k.Is("Date"))
{
myRequest.Date = val.AsDateTime();
}
else if (k.Is("Host"))
{
myRequest.Host = val;
}
else if (k.Is("Referer"))
{
myRequest.Referer = val;
}
else if (k.Is("Transfer-Encoding"))
{
myRequest.TransferEncoding = val;
}
else if (k.Is("User-Agent"))
{
myRequest.UserAgent = val;
}
//else if (k.Is("Connection"))
//{
// o.Connection = val;
//}
else if (k.Is("KeepAlive"))
{
myRequest.KeepAlive = val.AsBool();
}
}
return true;
}); using (var readStream = Request.InputStream)
{
while (true)
{
byte[] readBuffer = new byte[];
var readLength = readStream.Read(readBuffer, , readBuffer.Length);
if (readLength == ) break;
myRequest.GetRequestStream().Write(readBuffer, , readLength);
}
} new RequestWrap(myRequest).Run(myResponse =>
{
myResponse.Headers.AllKeys.All(k =>
{
if (k.Is("X-Powered-By"))
{
return true;
}
Response.Headers[k] = myResponse.Headers[k];
return true;
}); using (var readStream = myResponse.GetResponseStream())
{ while (true)
{
byte[] readBuffer = new byte[];
var read = readStream.Read(readBuffer, , readBuffer.Length);
if (read == ) break;
Response.OutputStream.Write(readBuffer, , read);
}
}
Response.StatusCode = myResponse.StatusCode.AsInt();
});
Response.End();
} public static string GetClientIPAddress()
{
if (HttpContext.Current == null)
return string.Empty;
HttpContext context = HttpContext.Current;//System.Web.HttpContext.Current; string ipAddress = context.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; if (!string.IsNullOrEmpty(ipAddress))
{
string[] addresses = ipAddress.Split(',');
if (addresses.Length != )
{
return addresses[];
}
} return context.Request.ServerVariables["REMOTE_ADDR"]; //+ " host " + context.Request.UserHostAddress;
} private string GetTransferHost()
{
string[] hosts = new string[] { "http://localhost" }; var index = GetClientIPAddress().Last() % hosts.Length ; return hosts[index];
}
解释
其中, RequestWrap 是对异步请求包装的请求类。封装了一个 Run 方法进行异步调用。过滤了应用服务器的回发头 X-Powered-By
关于 WebHeaderCollection.IsRestricted ,是由于一个错误引出的: 异常处理:必须使用适当的属性或方法修改此标头,文章地址: http://blog.useasp.net/archive/2013/09/03/the-methods-to-dispose-http-header-cannot-add-to-webrequest-headers.aspx,摘录如下:
你可以在这里设置其他限制的标头.
注意:
Range HTTP标头是通过AddRange来添加
If-Modified-Since HTTP标头通过IfModifiedSince 属性设置
Accept由 Accept 属性设置。
Connection由 Connection 属性和 KeepAlive 属性设置。
Content-Length由 ContentLength 属性设置。
Content-Type由 ContentType 属性设置。
Expect由 Expect 属性设置。
Date由 Date属性设置,默认为系统的当前时间。
Host由系统设置为当前主机信息。
Referer由 Referer 属性设置。
Transfer-Encoding由 TransferEncoding 属性设置(SendChunked 属性必须为 true)。
User-Agent由 UserAgent 属性设置。
流媒体返回头特征
Status : OK
Status_Code : 200
Connection : keep-alive
Accept-Ranges : bytes
Content-Length : 2373825
Content-Type : video/mp4
Date : Sun, 17 Apr 2016 02:39:17 GMT
Last-Modified : Fri, 15 Apr 2016 10:51:35 GMT
Server : nginx/1.9.3
C#手动做一个负载均衡服务器的更多相关文章
- 配置一个nginx反向代理&负载均衡服务器
一.基本信息 系统(L):CentOS 6.9 #下载地址:http://mirrors.sohu.com 反代&负载均衡(N):NGINX 1.14.0 #下载地址:http://nginx ...
- [link] 构建负载均衡服务器之一 负载均衡与集群详解
一.什么是负载均衡 首先我们先介绍一下什么是负载均衡: 负载平衡(Load balancing)是一种计算机网络技术,用来在多个计算机(计算机集群).网络连接.CPU.磁盘驱动器或其他资源中分配负载, ...
- Nginx(七):keepalived实现Nginx负载均衡服务器的双机高可用
前言 之前咱们通过 Nginx(六):Nginx HTTP负载均衡和反向代理的配置与优化 和 Nginx+tomcat组合实现高并发场景的动静分离和负载均衡方案 这两篇文章了解了Nginx对高并发应用 ...
- 用 LVS 搭建一个负载均衡集群(转)
http://blog.jobbole.com/87503/ 第一篇:<如何生成每秒百万级别的 HTTP 请求?> 第二篇:<为最佳性能调优 Nginx> 第三篇:<用 ...
- Nginx之负载均衡服务器揭秘
Nginx代理服务器, 一次性代理多台后端机器, 利用负载算法, 决定将当前请求传递给某台服务器执行. 有哪些后台服务器?例如微软的IIS,Apache,Nginx 负载算法是什么? 加权轮询. ng ...
- 如何使用Weave以及Docker搭建Nginx反向代理/负载均衡服务器
Hi, 今天我们将会学习如何使用 Weave 和 Docker 搭建 Nginx 的反向代理/负载均衡服务器.Weave 可以创建一个虚拟网络将 Docker 容器彼此连接在一起,支持跨主机部署及自动 ...
- Nginx系列~负载均衡服务器与WWW服务器的实现
上两讲主要是关于Nginx的环境的介绍,没有涉及到真正环境的开发,这次我们以一个实现的例子,来说明一下负载均衡服务器与WWW服务器的Nginx是如何配置的,并最终如何实现的. 如下是一个实际场景,一台 ...
- 6.Nginx作为负载均衡服务器应用
案例:Nginx作为负载均衡服务器应用 nginx的负载均衡功能是通过upstream命令实现的,因此他的负载均衡机制比较简单,是一个基于内容和应用的7层交换负载均衡的实现.Nginx负载均衡默认对后 ...
- nginx作为负载均衡服务器——测试
i. 需求 nginx作为负载均衡服务器,用户请求先到达nginx,再由nginx根据负载配置将请求转发至 tomcat服务器. nginx负载均衡服务器:192.168.101.3 tomcat1服 ...
随机推荐
- 使用SftpDrive+SourceInsight阅读开源代码
在虚拟机环境下使用Linux编写和阅读代码,我之前一直是通过Xshell利用ssh登录至虚拟机从而在命令行下使用vim来进行的.目前有阅读开源代码的需要,虽然vim+ctags+cscope可以完成这 ...
- jQuery 屏幕遮罩
1.先做一个可以覆盖整个屏幕的div,颜色为黑色,然后再设置透明度,作为遮罩#zhezhao { position: absolute; top: 0px; left: 0px; width: 100 ...
- Python基础(七)内置函数
今天来介绍一下Python解释器包含的一系列的内置函数,下面表格按字母顺序列出了内置函数: 下面就一一介绍一下内置函数的用法: 1.abs() 返回一个数值的绝对值,可以是整数或浮点数等. 1 2 3 ...
- C语课设心得分享(三)
调试. 以前咱们写课后习题,一般也不需要使用调试,如果程序编译error,根据错误信息就可以改好:如果是结果错误,那么在稿纸上过几遍基本也可以得出结果. 但咱们这个课设比较大,就需要很多调试的过程,尤 ...
- java.net.MalformedURLException: Illegal character in URL
在进行接口测试时,意外发现返回结果报java.net.MalformedURLException: Illegal character in URL,意思是“在URL中的非法字符”,我的参数是经过ba ...
- SQL获取所有数据库名、表名、储存过程以及参数列表
SQL获取所有数据库名.表名.储存过程以及参数列表 1.获取所有用户名:SELECT name FROM Sysusers where status='2' and islogin='1'islogi ...
- c语言检测文件是否存在int __cdecl access(const char *, int);
最近写代码,遇到很多地方需要判断文件是否存在的.网上的方法也是千奇百怪,“百家争鸣”. fopen方式打开的比较多见,也有其他各种方式判断文件是否存在的,由于其他方法与本文无关,所以不打算提及. 笔者 ...
- Android.技术站点
总结Android相关的技术站点和blog 1. http://android-developers.blogspot.com/ 首推这个blog,有时间需要每篇blog读一遍. 2. nlopez ...
- 管道导致的while循环体变量失效
#!/bin/sh num= cat /etc/passwd | while read line do num=$(($num+)) done echo $num linux:~ # sh a.sh ...
- JS 获取服务器时间
function getSevertime(){ var xmlHttp = new XMLHttpRequest(); xmlHttp.open("get",location.h ...