我将系统从Windows迁移至Linux下的点点滴滴

1、写在最前

  因为本人的技术水平有限,不免会出现错误。本文对任何一我的有帮助都是我莫大的荣幸,任何一个大神对个人点拨,我都会感激涕零。linux

2、技术选型

  在2013年8月低的时候,公司中了XXX市场监督局肉品配送车辆监控的项目。整个系统软件部分须要实现的功能不难,最大的难点就是服务器的系统要求是Linux的,其次就是10月底系统可以初步成型。因为以前作的车辆监控系统都基于Windows的,要在短期内完成这个项目,因而Mono就成了个人首选。张善友的博客,也成了我常常光顾的地方,后来经过跟张哥的一番沟通。最终采用了张哥推荐的方案,数据库使用PostgreSQL,Web服务器使用国产的Jexus,Linux操做系统使用CentOS6.2(这个是客户要求的)。其余均可以很好移植,以前的系统前台使用的Extjs+SilverLight+Asp.net,服务层使用的WCF,当时张哥有提醒我Mono下的WCF坑特别的多,ORM使用的是Nhibernate,地图引擎依旧采用的DeepEarth。有张哥的点拨,个人信心满满的。看上去彷佛我须要解决的问题就是搭建好Mono环境,搞定Mono下的WCF服务就能够大功告成了。sql

3、环境搭建

  装Linux系统,配置Mono环境,安装Jexus。写了个简单的Silverlight + WCF的程序部署到Jexus,居然成功跑来了,当时的我偷笑了。然而,当我真正把系统部署到Jexus上面,才知道噩梦才刚刚开始。登陆页面都没有过不去,此时估计不少人都会想要是在Linux下能Debug就行了,我也不例外。因而乎,我就折腾MonoDevelop,安装过程当中遇到各类奇葩问题,并且不支持SilverLight的项目,我放弃了。采用最原始的办法,写日志。通过几天的折腾,终于能够跑起来了。数据库

4、WCF攻克

  因为在折腾WCF的时候,遇到的默默其妙的问题比较多,有些可以经过Google搜索到。我这里就列举三个。服务器

  1:寻址版本 AddressingNone不支持添加 WS-Addressing 标头。若是你的WCF部署在IIS下能正常的调用,而部署在Jexus下确抛出这种异常。session

  检查项目下引用的dll,估计某些dll在Mono下支持不是很好。在有可能出错的异常写日志,而不要抛出这个异常。好比下面这个简单的例子,FluentNhibernate在Mono下的支持就不是很好。并发

 public IList<Custmer> GetCustoemrs()
        {
            try
            {
                using (var session = SessionFactory.GetCurrentFactory().OpenSession())
                {
                    var query = session.CreateQuery("from Customer ");
                    return query.List<Customer>();
                }
            }
            catch (Exception ex)
            {
                LogHelper.WriteException("GetCustomers method raise error:", ex);
                //throw;
            }
        }

        public class SessionFactory
        {
            public static ISessionFactory GetCurrentFactory()
            {
                return sessionFactory ?? (sessionFactory = CreateSessionFactory());
            }

            private static ISessionFactory CreateSessionFactory()
            {
                return Fluently.Configure()
                      .Database(MsSqlConfiguration.MsSql2008.ConnectionString(
                                     x => x.FromConnectionStringWithKey("db")))
                    .Mappings(m => m.FluentMappings.AddFromAssemblyOf<CustomerMap>())
                    .BuildSessionFactory();
            }

            private static ISessionFactory sessionFactory
            {
                get;
                set;
            }
        }

  2:客户端反序列化失败app

  当我把WCF部署到Jexus,成功生成本地代理后,调用WCF就会一直报这个错误。究其缘由,就是由于生成代理类的属性指定了反序列化的顺序,而服务端我是没有指定的。因此,先把WCF服务部署到IIS下,而后客户端地址指向部署IISWCF服务,从新更新服务,再把配置文件中地址指向部署在JexusWCF服务便可。工具

Jexus下Host的WCF服务生成的本地代理:post

[System.Runtime.Serialization.DataMemberAttribute(IsRequired=true, Order=1)]
        public string CustomerCode {
            get {
                return this.CustomerCodeField;
            }
            set {
                if ((object.ReferenceEquals(this.CustomerCodeField, value) != true)) {
                    this.CustomerCodeField = value;
                    this.RaisePropertyChanged("CustomerCode");
                }
            }
        }

IIS下Host的WCF服务生成的本地代理:测试

 [System.Runtime.Serialization.DataMemberAttribute()]
        public string CustomerCode {
            get {
                return this.CustomerCodeField;
            }
            set {
                if ((object.ReferenceEquals(this.CustomerCodeField, value) != true)) {
                    this.CustomerCodeField = value;
                    this.RaisePropertyChanged("CustomerCode");
                }
            }
        }

  3WCF服务致使Jexushttpd worker不断重启

  这个问题是困扰我最久的,在IE11下最为明显,Service.svc文件的post请求,动不动就被Pending。在最开始我不知道Jexus一直在重启,由于我看jws.log中没有Jexus重启的日志。后来得知能够经过 ps –ef | grep jws 指令能够查看进程的启动时间,以下图所示,能够看到httpd worker进程不断的重启。

  问题找到了,又开始新的一轮折腾。首先,减小客户端对Service.svc文件的post请求,其次将WCF回传的数据进行压缩处理。一番修改后,IE11下,故障依旧。因而想到了用WebService尝试下,就把某个服务修改为WebService的方式后,貌似httpd worker不会重启了,处理不过来请求的时候,只会中断请求。既然这样,我就狠心把WCF的绑定方式由CustomBinding的方式改为了BasicHttpBinding,然而故障仍是那么的顽固存在。

  通过一番测试,感受多是Jexus的问题,测试代码:

class Program
    {
        private static ServiceClient client;
        private static int count = 0;
        static void Main(string[] args)
        {
            client = new ServiceClient();
            client.GetCustomersCompleted += client_GetCustomersCompleted;
            int callCount = Convert.ToInt32(ConfigurationManager.AppSettings["CallCount"]);
            Console.WriteLine("Press begin to Call WCF Service:");
            while (Console.ReadLine().ToLower() == "begin")
            {
                DoWork(callCount);
            }
            Console.Read();
        }
        private static void DoWork(int callCount)
        {
            for (int i = 1; i <= callCount; i++)
            {
                ThreadPool.QueueUserWorkItem(CallService, i);
            }
        }
        private static void CallService(object state)
        {
            client.GetCustomersAsync(state);
        }
        static void client_GetCustomersCompleted(object sender, GetCustomersCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                Interlocked.Add(ref count, 1);
                Console.WriteLine("成功调用:{0}", count);
            }
            else
            {
                Console.WriteLine(e.Error);
            }
        }
    }
}

  若是是对WebService模拟并发发起请求的时候,httpd worker不会重启,若是是WCFhttpd worker会不断的重启。没有办法只有咨询Jexus的做者宇内了。跟他描述了问题,按照他说的更新了Jexus版本,优化了Linux。最后发了个测试工具给宇内,宇内发现Jexus在处理WCF请求的时候是有点问题。在这里仍是要感谢宇内那么热心的帮助我解决问题。

5、数据库迁移

     数据库的迁移遇到的问题不是不少,借助navicat将数据从SqlServer导入到PostgreSQL。因为系统的业务不是很复杂,以前就采用了Nhibernate,须要修改配置文件中主键字段的映射,由于PostgreSQL中采用的是序列。以前SqlServer中一些稍微复杂点的查询是采用存储过程写的,存储过程的移植性很差,在PostgresSQL下这部分只能从新写了。

<id name="TypeID" type="Int32" unsaved-value="0">
           <column name="TypeID" length="4" sql-type="int" not-null="true" unique="true" index="PK_SysAllType"/>
      <generator class="sequence">
        <param name="sequence">sysalltype_typeid_seq</param>
      </generator>
</id>

6、地图迁移

  因为地图服务器是单独一台,最终是用Perl + Apache来实现的,实现也挺简单的,几十行代码,就是地图引擎请求一个图片路径,将图片输出就能够了。最开始的时候,用的是Asp.net,部署在Jexus上,可是不知道为何某些图片始终输出不出来,最终仍是放弃了。

最后附上一张系统迁移后成功后的图片:

相关文章
相关标签/搜索