C \ # 수 동 으로 부하 균형 서버 만 들 기

13786 단어
사고의 방향
부하 균형 서버 의 가장 유명한 숫자 는 Nginx 입 니 다.Nginx 서버 는 내부 네트워크 와 N 개 서버 에 비동기 적 으로 연결 을 전송 하여 단일 응용 서버 의 압력 을 분해 하고 원리 와 장면 을 파악 한 후 C \ # 로 하 나 를 실현 합 니 다.사고방식 은 다음 과 같다.
1. 한 사이트 의 Application_BeginRequest 에서 연결 을 받 고 전송 합 니 다.
2. 각종 정적 자원 에 대해 단독 처 리 를 한다. (돌 릴 수 있 고 돌 릴 수 없다)
3. Get, Post, 비동기 리 트 윗 이 가능 합 니 다.
4. 지정 한 요청 을 같은 서버 에 전송 하여 사용자 의 로그 인 상 태 를 유지 합 니 다.
이루어지다
Vs 2015 Mvc 건설 소: localhost: 1500 /.웹. 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(15000);
            }

            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 > 0)
                {
                    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 = 15000;
            myRequest.ReadWriteTimeout = 3000;

            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[1024];
                    var readLength = readStream.Read(readBuffer, 0, readBuffer.Length);
                    if (readLength == 0) break;
                    myRequest.GetRequestStream().Write(readBuffer, 0, 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[1024];
                        var read = readStream.Read(readBuffer, 0, readBuffer.Length);
                        if (read == 0) break;
                        Response.OutputStream.Write(readBuffer, 0, 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 != 0)
                {
                    return addresses[0];
                }
            }

            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 
... 에 대하 여 WebHeader Collection. 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 。
 
그 중: Connection 설정 이 틀 릴 수 있어 서 제 가 걸 었 습 니 다.

좋은 웹페이지 즐겨찾기