分布式服务框架的热挂载以及多版本共存的简析与实现

现行的网络服务要想做大做好必须朝着分布式服务的方向去发展,比如阿里巴巴、京东这种大型的电子商务网站平台都采用了具有各自特色的分布式服务框架。分布式服务框架就是将各种服务挂载在不同的服务器上,然后进行整体的调度管理对外提供网络服务。

本博文主要讲解分布式服务的热挂载以及多版本服务共存的原理和实现,热挂载顾名思义就是在不停止框架服务进程的情况下挂载服务。

首先要实现服务的热挂载无非就是两种方式,一种是需要部署服务时候的手动操作,以及服务框架的主动监测。在这里讲解更加智能化的框架主动监测以及实现。

要实现框架的主动监测服务兵实现热挂载

(1)定时器扫描服务契约目录,监测是否有新的服务契约上传,有的话挂载上该服务。

(2)利用消息通知被动触发服务热挂载操作。这块其实底层也是封装的定时器。

所以热挂载其实就是服务框架的定时扫描契约路径,发现新的服务契约,然后进行服务挂载。

发现服务契约之后,框架要进行的操作就是为该服务提供一个独立的运行文件夹,然后把服务运行在这个文件空间里面,但是上面又提到了多版本共存,所以这里又涉及到了一个读取服务契约版本的问题。

我的实现方式是:

(1)监测到新的打包好的服务契约文件之后,生成一个临时文件夹,把契约文件解压到该临时文件夹,然后读取该服务的服务版本,把该临时文件夹重命名为服务名和版本号的组合比如服务HelloService版本号为1.0.0.1,则我就为该版本的服务建立一个HelloService_1.0.0.1的独立服务路径

(2)然后将我的服务宿主程序拷贝到该目录下,然后运行挂载程序,挂载该服务对外提供网络服务。

(3)并在服务列表添加该服务的信息

服务契约代码如下(生成DLL为SelfHost.ServiceInterface.dll):

using ServiceStack;

namespace SelfHost.ServiceInterface
{
    public class MyServices : Service
    {
        public object Any(Hello request)
        {
            return new HelloResponse { Result = string.Format("Hello, {0}!",request.Name) };
        }

    }

    [Route("/hello/{Name}")]
    public class Hello : IReturn<HelloResponse>
    {
        public string Name { get; set; }
    }

    public class HelloResponse
    {
        public string Result { get; set; }
    }
}

分布式服务框架的测试程序代码如下(其中涉及一些子进程):

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using System.IO;
namespace ConsoleApplication3
{
    class Program
    {
        public static Dictionary<string, int> Serviceinfo = new Dictionary<string, int>();
        private static readonly string Dir = Environment.CurrentDirectory;
        private static readonly string Wpath = Environment.CurrentDirectory + @"\WorkDir";
        private static readonly string Cpath = Environment.CurrentDirectory + @"\ServiceContract";
        private static readonly string HostExe = Environment.CurrentDirectory + @"\HostPacket\ServiceHost.rar";

        static void Main(string[] args)
        {
             GetServiceInfo();
             Console.ReadLine();
        }

        public static int SrartService(string dllasoDir, string bindadd, string servicename,string hostdir)
        {
            Process pro = new Process();
            pro.StartInfo.FileName = hostdir;
            //pro.StartInfo.UseShellExecute = false;
            pro.StartInfo.Arguments = dllasoDir + " " + bindadd + " " + servicename;
            pro.Start();
            return pro.Id;
        }

        /// <summary>
        /// 准备服务目录的宿主程序
        /// </summary>
        /// <returns></returns>
        private static bool PrepareService(string desfolder)
        {
            try
            {
                Process pro = new Process();
                pro.StartInfo.FileName = Dir + @"\OutEXE\WinRAR\WinRAR.exe";
                pro.StartInfo.Arguments = " x " + HostExe + " " + desfolder + " -iback -y";
                pro.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                pro.Start();
                pro.WaitForExit();
                pro.Close();
                //TODO 把SELFHOST命名成目的服务名
                FileInfo fi = new FileInfo(desfolder + "SelfHost.exe");
                var data = desfolder.Split(‘\\‘);
                var name = data[data.Length - 2];
                string hostdir = desfolder + name + ".exe";
                fi.MoveTo(hostdir);
                //TODO 启动宿主进程
                int i = SrartService(desfolder + name.Substring(0, name.IndexOf(‘_‘))+".dll", "http://*:8055/", "HelloService " ,hostdir);
                Serviceinfo.Add(name,i);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Message:" + ex.Message + "\r\n");
                Console.WriteLine("StackTrace:" + ex.StackTrace);
                return false;
            }
            return true;
        }

        /// <summary>
        /// 获取服务契约目录下的压缩文件
        /// </summary>
        private static void GetServiceInfo()
        {
            if (!Directory.Exists(Wpath))
            {
                Directory.CreateDirectory(Wpath);
            }
            if (Directory.Exists(Cpath))
            {
                var files = Directory.GetFiles(Cpath, "*.zip");
                foreach (var item in files)
                {
                    InitServiceContract(item.ToString());
                }
            }
            else
            {
                Directory.CreateDirectory(Cpath);
            }
        }

        /// <summary>
        /// 初始化服务契约文件
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        public static bool InitServiceContract(string filename)
        {
            string strGUID = System.Guid.NewGuid().ToString();
            string desdir = Wpath + @"\" + strGUID + @"\";
            Process pro = new Process();
            pro.StartInfo.FileName = Dir + @"\OutEXE\WinRAR\WinRAR.exe";
            pro.StartInfo.Arguments = "x " + filename + " " + desdir + " -iback -y";
            pro.Start();
            pro.WaitForExit();
            pro.Close();
            string[] buff = filename.Split(‘\\‘);
            string singlename = buff.ElementAt(buff.Length - 1);
            singlename = singlename.Replace(".zip", ".dll");
            string tempdir = Wpath + @"\" + strGUID + @"\" + singlename;
            string version = GetDllVersion(tempdir);
            string key = filename.Replace(".dll", "") + "_" + version;
            if (Serviceinfo.ContainsKey(key) || Directory.Exists(Wpath + @"\" + singlename.Replace(".dll", "") + "_" + version))
            {
                Console.WriteLine("已挂载服务:" + singlename + "\t版本号:" + version);
                Directory.Delete(Wpath + @"\" + strGUID, true);
                return false;
            }
            else
            {
                string desfolder = Wpath + @"\" + singlename.Replace(".dll", "") + "_" + version;
                Directory.Move(Wpath + @"\" + strGUID, desfolder);
                PrepareService(desfolder + @"\");
            }
            return true;
        }

        /// <summary>
        /// 调用子进程获取版本号
        /// </summary>
        /// <param name="filename">dll路径</param>
        /// <returns></returns>
        public static string GetDllVersion(string filename)
        {
            Process pro = new Process();
            pro.StartInfo.FileName = Dir + @"\OutEXE\MyTool\GetDllVersion.exe";
            pro.StartInfo.Arguments = filename;
            pro.StartInfo.UseShellExecute = false;
            pro.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            pro.StartInfo.RedirectStandardOutput = true;
            pro.Start();
            string str = pro.StandardOutput.ReadLine().ToString();
            pro.WaitForExit();
            pro.Close();
            return str;
        }
    }
}

程序的运行路径截图如下:

其中OutEXE里面其实就是一个WINRAR解压程序包,以及我的契约版本获取进程,这儿不得不提的就是在获取器乐版本并进行文件夹的重命名的时候,涉及到操作系统的资源引用的问题,所以上述操作在一个进程内无法完成,所以写了一个获取DLL版本的小程序,通过子程序的方式获DLL版本号。

该程序代码如下:

using System;
using System.Reflection;

namespace GetDllVersion
{
    public class Program
    {
        static void Main(string[] args)
        {
            Assembly ass = Assembly.LoadFile(args[0]);
            AssemblyName assemblyName = ass.GetName();
            Version version = assemblyName.Version;
            Console.WriteLine(version.ToString());
        }
    }
}

这儿只是实现了一个小DEMO实现了服务的热挂载以及多版本共存,真正用到生产环节还要进行进一步的优化。

示例框架使用流程:

(1)定义好服务契约如上所示,打包压缩并将压缩文件名定位DLL名

(2)然后将服务契约压缩文件拷贝到ServiceContract目录下框架将自动进行服务的挂载

OK!

时间: 2024-10-22 09:29:38

分布式服务框架的热挂载以及多版本共存的简析与实现的相关文章

分布式服务框架Dubbo

随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进. 单一应用架构 当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本. 此时,用于简化增删改查工作量的 数据访问框架(ORM) 是关键. 垂直应用架构  当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率. 此时,用于加速前端页面开发的 Web框架(MVC) 是关键. 分布式服

分布式服务框架 Zookeeper -- 管理分布式环境中的数据

安装和配置详解 Zookeeper 分布式服务框架是 Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务.状态同步服务.集群管理.分布式应用配置项的管理等.本文将 从使用者角度详细介绍 Zookeeper 的安装和配置文件中各个配置项的意义,以及分析 Zookeeper 的典型的应用场景(配置文件的管理.集群管理.同步锁.Leader 选举.队列管理等),用 Java 实现它们并给出示例代码. 单机模式 单 机安装非常简单,只要获取

分布式服务框架下,如何做到服务化最佳实践?

“升级服务框架后,性能.可靠性等问题日益明显.服务化之后面临的诸多挑战,怎样分析才能给出实践最优解? 在服务化之前,业务通常都是本地API调用,本地方法调用性能损耗较小.服务化之后,服务提供者和消费者之间采用远程网络通信,增加了额外的性能损耗,业务调用的时延将增大,同时由于网络闪断等原因,分布式调用失败的风险也增大.如果服务框架没有足够的容错能力,业务失败率将会大幅提升. 除了性能.可靠性等问题,跨节点的事务一致性问题.分布式调用带来的故障定界困难.海量微服务运维成本增加等也是分布式服务框架必须

【转】分布式服务框架 Zookeeper -- 管理分布式环境中的数据

Zookeeper 分布式服务框架是 Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务.状态同步服务.集群管理.分布式应用配置项的管理等.本文将从使用者角度详细介绍 Zookeeper 的安装和配置文件中各个配置项的意义,以及分析 Zookeeper 的典型的应用场景(配置文件的管理.集群管理.同步锁.Leader 选举.队列管理等),用 Java 实现它们并给出示例代码. 安装和配置详解 本文介绍的 Zookeeper 是以 3

java分布式服务框架Dubbo的介绍与使用

1. Dubbo是什么? Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案.简单的说,dubbo就是个服务框架,如果没有分布式的需求,其实是不需要用的,只有在分布式的时候,才有dubbo这样的分布式服务框架的需求,并且本质上是个服务调用的东东,说白了就是个远程服务调用的分布式框架(告别Web Service模式中的WSdl,以服务者与消费者的方式在dubbo上注册)其核心部分包含:1. 远程通讯: 提供对多种基于长连接的NIO框架抽象封装,

分布式服务框架Dubbo入门案例和项目源码

本项目源代码:http://download.csdn.net/detail/fansunion/9498406 Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案, 是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000+次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点.   官方网站: http://dubbo.io/ 本项目代码,根据官方提供的dubbo-ws-demo-master例子,改造而来.    官网例子

分布式服务框架学习笔记1 应用架构演进

传统垂直应用架构 业界曾比较流行的有: LAMP架构:Linux+Apache+PHP(前后端分离)+MySQL(读写分离) MVC架构:Spring+Struts+iBatis/Hibernate+Tomcat 在高并发.大流量的应用场景中,需要做集群,通常的组网方案是前端通过F5等负载均衡器做七层负载均衡(或者使用SLB等软负载),后端做对等集群部署. 随着业务的不断发展,应用规模日趋庞大,传统垂直架构开发模式的弊端变得越来越突出.这就需要将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服

【转】Dubbo是Alibaba开源的分布式服务框架

Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合).从服务模型的角度来看,Dubbo采用的是一种非常简单的模型,要么是提供方提供服务,要么是消费方消费服务,所以基于这一点可以抽象出服务提供方(Provider)和服务消费方(Consumer)两个角色.关于注册中心.协议支持.服务监控等内容,详见后面描述. 总体架构 Dubbo的总体架构,如图所示: Dubbo框架设计一共划分了10个层,而最上面的Serv

分布式服务框架Dubbo使用小结

介绍: Dubbo是一个被国内很多互联网公司广泛使用的开源分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA 服务治理方案,每天为2,000+个服务提供3,000,000,000+次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点. 其核心部分包含: 远程通讯: 提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型,序列化,以及"请求-响应"模式的信息交换方式. 集群容错: 提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,