nginx代理与负载均衡

9 篇文章 1 订阅
4 篇文章 0 订阅

随着谷歌浏览器不断的改变https调用websocket和非https资源的策略,从谷歌大概70以后不允许https调用非https资源和ws的websocket。后面实现了wss解决谷歌这一策略的影响。随着谷歌到90后版本限制了私有证书的调用,导致最新浏览器又不能调用wss的websocket了。一方面是安保要求https传输,一方面是谷歌不断加严格https策略和证书策略,有好一段时间竟然有点难两全了。

最近想起在linux试nginx的反向代理可以代理url,然后它还有负载均衡的功能。可不可以给客户端运行个nginx把https代理为http。顺带也实现了负载均衡呢?

有几个问题需要验证:
1.windows的nginx部署是否麻烦?
2.windows的nginx包是否太大?

如果需要安装或者包太大那么不可行。前几天用nginx正好解决了http调用https润乾页面老是要信任证书的问题。整个windows的nginx包就几兆。而且不需要安装,运行也是后台的,所以符合需求。

那么就可以自己用C#写个负载均衡启动程序,程序设计流程如下。

在这里插入图片描述

实现控制台代码如下:

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Diagnostics;

namespace LISLoadBalance
{
    /// <summary>
    /// 实现负载均衡启动网站
    /// </summary>
    class Program
    {
        /// <summary>
        /// 程序入口
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            //尝试启动nginx
            string openUrl = TryStartNginx();
            //打开本地地址
            if (openUrl != "")
            {
                OpenChromeUtil.OpenUrl(openUrl);
            }
            Environment.Exit(0);
        }

        /// <summary>
        /// 尝试打开nginx
        /// </summary>
        public static string TryStartNginx()
        {
            try
            {
                string nginxConfPath = "C:\\TRAK\\nginx\\conf\\nginx.conf";
                //不存在负载均衡文件就不打开
                if (!File.Exists(nginxConfPath))
                {
                    MessageBox.Show(nginxConfPath + "不存在!", "提示", MessageBoxButtons.OK);
                    return "";
                }
                //读取nginx配置
                string confStr = TxtUtil.ReadTxt(nginxConfPath);
                //从第一行取到配置更新地址
                string updateUrl = confStr.Split((char)13)[0];
                updateUrl = updateUrl.Replace("#", "");
                //本地打开的地址
                string openUrl = confStr.Split((char)13)[1];
                openUrl = openUrl.Replace("#", "").Replace((char)10 + "", "");
                //得到服务器的配置
                string confStrServer = GetServerConf(updateUrl);
                //服务配置变化之后停止niginx
                if (confStrServer != "" && confStrServer != confStr)
                {
                    //杀掉nginx进程
                    foreach (Process p in System.Diagnostics.Process.GetProcessesByName("nginx"))
                    {
                        try
                        {
                            p.Kill();
                            p.WaitForExit();
                        }
                        catch (Exception exp)
                        {
                            Console.WriteLine(exp.Message);
                            System.Diagnostics.EventLog.WriteEntry("AlchemySearch:KillProcess", exp.Message, System.Diagnostics.EventLogEntryType.Error);
                        }
                    }
                    //写入新的配置
                    TxtUtil.WriteTxt(nginxConfPath, confStrServer, true);
                }
                //没有启动nginx就启动
                bool hasStart = false;
                //检查nginx是否启动
                foreach (Process p in System.Diagnostics.Process.GetProcessesByName("nginx"))
                {
                    hasStart = true;
                }
                //没nginx启动就尝试启动
                if (hasStart == false)
                {
                    string nginxPath = "C:\\TRAK\\nginx\\nginx.exe";
                    if (File.Exists(nginxPath))
                    {
                        Process.Start(nginxPath);
                        System.Threading.Thread.Sleep(1000);
                    }
                    else
                    {
                        MessageBox.Show(nginxPath + "不存在!", "提示", MessageBoxButtons.OK);
                    }
                }
                return openUrl;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "提示", MessageBoxButtons.OK);
                return "";
            }
        }

        /// <summary>
        /// 得到服务器的配置
        /// </summary>
        /// <param name="updateUrl"></param>
        /// <returns></returns>
        private static string GetServerConf(string updateUrl)
        {
            HttpWebRequest request = null;
            try
            {
                if (updateUrl.StartsWith("https", StringComparison.OrdinalIgnoreCase))
                {
                    request = WebRequest.Create(updateUrl) as HttpWebRequest;
                    ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                    request.ProtocolVersion = HttpVersion.Version11;
                    // 这里设置了协议类型。
                    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
                    request.KeepAlive = false;
                    ServicePointManager.CheckCertificateRevocationList = true;
                    ServicePointManager.DefaultConnectionLimit = 100;
                    ServicePointManager.Expect100Continue = false;
                }
                else
                {
                    request = (HttpWebRequest)WebRequest.Create(updateUrl);
                }
                HttpWebResponse response = request.GetResponse() as HttpWebResponse;
                Stream responseStream = response.GetResponseStream();
                StreamReader myread = new StreamReader(responseStream);
                string serverStr = myread.ReadToEnd();
                responseStream.Close();
                return serverStr;
            }
            catch (Exception ex)
            {
                MessageBox.Show("从主站点获取nginx配置失败:" + ex.Message, "提示", MessageBoxButtons.OK);
                return "";
            }
        }


        /// <summary>
        /// 回调
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="certificate"></param>
        /// <param name="chain"></param>
        /// <param name="errors"></param>
        /// <returns></returns>
        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            //总是接受  
            return true;
        }


    }
}

OpenChromeUtil.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace LISLoadBalance
{
    /// <summary>
    /// 打开谷歌浏览器工具类
    /// </summary>
    public class OpenChromeUtil
    {
        /// <summary>
        /// 打开url
        /// </summary>
        /// <param name="loginPath"></param>
        public static void OpenUrl(string loginPath)
        {
            string chromePath = "";
            bool IsChrome = TryGetSoftwarePath("chrome", out chromePath);
            if (IsChrome && chromePath.Length > 0)
            {
                System.Diagnostics.Process.Start(chromePath, "--app="+loginPath);
            }
            else
            {
                Process pro = new Process();
                //文件路径
                pro.StartInfo.FileName = loginPath;
                pro.StartInfo.CreateNoWindow = true;
                pro.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                pro.StartInfo.Verb = "Open";
                pro.Start();
            }
        }

        /// <summary>
        /// 获取某个安装文件的执行路径
        /// </summary>
        /// <param name="softName">软件名</param>
        /// <param name="path">路径</param>
        /// <returns></returns>
        public static bool TryGetSoftwarePath(string softName, out string path)
        {
            string strPathResult = string.Empty;
            string strKeyName = "";     
            object objResult = null;

            Microsoft.Win32.RegistryValueKind regValueKind;
            Microsoft.Win32.RegistryKey regKey = null;
            Microsoft.Win32.RegistryKey regSubKey = null;

            try
            {
                //读取值
                regKey = Microsoft.Win32.Registry.LocalMachine;
                regSubKey = regKey.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\" + softName.ToString() + ".exe", false);

                //如果在LocalMachine获取不到,可以在CurrentUser里获取
                if (regSubKey == null)
                {
                    regKey = Microsoft.Win32.Registry.CurrentUser;
                    regSubKey = regKey.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\" + softName.ToString() + ".exe", false);
                }

                //读路径
                objResult = regSubKey.GetValue(strKeyName);
                regValueKind = regSubKey.GetValueKind(strKeyName);

                //设置路径
                if (regValueKind == Microsoft.Win32.RegistryValueKind.String)
                {
                    strPathResult = objResult.ToString();
                }
            }
            catch (System.Security.SecurityException ex)
            {
                path = "";
                MessageBox.Show("你没有读取注册表的权限! " + ex.Message, "提示", MessageBoxButtons.OK);
            }
            catch (Exception ex)
            {
                path = "";
                MessageBox.Show("读取注册表错误! " + ex.Message, "提示", MessageBoxButtons.OK);
            }
            finally
            {

                if (regKey != null)
                {
                    regKey.Close();
                    regKey = null;
                }

                if (regSubKey != null)
                {
                    regSubKey.Close();
                    regSubKey = null;
                }
            }

            if (strPathResult != string.Empty)
            {
                path = strPathResult;
                return true;
            }
            else
            {
                path = "";
                return false;
            }
        }
    }
}

TxtUtil.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;

namespace LISLoadBalance
{
    ///<summary  NoteObject="Class">
    /// [功能描述:文本工具类,提供文本操作] <para/>
    /// [创建者:zlz] <para/>
    /// [创建时间:2015年10月25日] <para/>
    ///<说明>
    ///  [说明:文本工具类,提供文本操作]<para/>
    ///</说明>
    ///<修改记录>
    ///    [修改时间:本次修改时间]<para/>
    ///    [修改内容:本次修改内容]<para/>
    ///</修改记录>
    ///<修改记录>
    ///    [修改时间:本次修改时间]<para/>
    ///    [修改内容:本次修改内容]<para/>
    ///</修改记录>
    ///</summary>
    public static class TxtUtil
    {
        /// <summary>
        /// 读取文件数据
        /// </summary>
        /// <param name="path">文件全路径</param>
        /// <returns></returns>
        public static string ReadTxt(string path)
        {
            //文件不存在
            if (!File.Exists(path))
            {
                return "";
            }
            FileStream fs = null;
            try
            {
                //要用不带BOM的utf8
                System.Text.UTF8Encoding utf8 = new System.Text.UTF8Encoding(false);
                fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                StreamReader sr = new StreamReader(fs, utf8);
                string str = sr.ReadToEnd();
                return str;
            }
            catch (Exception ex)
            {
                MessageBox.Show("读文件异常:" + ex.Message, "提示", MessageBoxButtons.OK);
                return "";
            }
            finally
            {
                fs.Close();
            }
        }

        /// <summary>
        /// 写入数据到指定文件
        /// </summary>
        /// <param name="path">文件全路径</param>
        /// <param name="str">数据</param>
        /// <param name="isReplace">是否提换,默认为替换,否则为添加</param>
        /// <returns></returns>
        public static bool WriteTxt(string path, string str, bool isReplace = true, Encoding ecod = null)
        {
            if (ecod == null)
            {
                //要用不带BOM的utf8
                System.Text.UTF8Encoding utf8 = new System.Text.UTF8Encoding(false);
                ecod = utf8;
            }
            FileStream fs = null;
            StreamWriter sw1 = null;
            try
            {
                //如果文件不存在,先创建一个
                if (!File.Exists(path))
                {
                    //创建写入文件  
                    fs = new FileStream(path, FileMode.Create, FileAccess.Write);
                    sw1 = new StreamWriter(fs, ecod);
                    //开始写入值  
                    sw1.WriteLine(str);
                }
                else
                {
                    //如果是替换,先清除之前的内容
                    if (isReplace)
                    {
                        using (StreamWriter sw = new StreamWriter(path, false, ecod))
                        {
                            sw.Write("");
                            sw.Close();
                        }
                    }
                    fs = new FileStream(path, FileMode.Append, FileAccess.Write);
                    sw1 = new StreamWriter(fs, ecod);
                    sw1.WriteLine(str);
                }
                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show("读文件异常:" + ex.Message, "提示", MessageBoxButtons.OK);
                return false;
            }
            finally
            {
                if (sw1 != null)
                {
                    sw1.Close();
                }
                if (fs != null)
                {
                    fs.Close();
                }
            }
        }
    }
}

对nginx配置约定加上前两行注释,以实现自动从服务器更新配置。达到在服务器维护负载信息的目的。
在这里插入图片描述
维护时候就只要把主web的nginx配置这里维护可用的负载服务器地址就行。客户端启动器就能及时得的负载列表,驱动nginx负载调用。
在这里插入图片描述

搞完了之后把编译的启动器和nginx以前打包放入网站服务器,让初始化程序初始化到本地桌面即可
在这里插入图片描述

然后就可以通过负载启动程序驱动登录了。
在这里插入图片描述

在这里插入图片描述

哈哈,说干就干。此模式不需要依赖别的组提供负载均衡。直接自己内部就实现负载,何其美哉。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小乌鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值