我將系統從Windows遷移至Linux下的點點滴滴


一、寫在最前

  由於本人的技術水平有限,難免會出現錯誤。本文對任何一個人有幫助都是我莫大的榮幸,任何一個大神對我的點撥,我都會感激不盡。

二、技術選型

  在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服務就可以大功告成了。

三、環境搭建

  裝Linux系統,配置Mono環境,安裝Jexus。寫了個簡單的Silverlight + WCF的程序部署到Jexus,竟然成功跑來了,當時的我偷笑了。然而,當我真正把系統部署到Jexus上面,才知道噩夢才剛剛開始。登錄頁面都沒有過不去,此時估計很多人都會想要是在Linux下能Debug就好了,我也不例外。於是乎,我就折騰MonoDevelop,安裝過程中遇到各種奇葩問題,而且不支持SilverLight的項目,我放棄了。采用最原始的辦法,寫日志。經過幾天的折騰,終於可以跑起來了。

四、WCF攻克

  由於在折騰WCF的時候,遇到的默默其妙的問題比較多,有些能夠通過Google搜索到。我這里就列舉三個。

  1:尋址版本 AddressingNone不支持添加 WS-Addressing 標頭。如果你的WCF部署在IIS下能正常的調用,而部署在Jexus下確拋出這種異常。

  檢查項目下引用的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:客戶端反序列化失敗

  當我把WCF部署到Jexus,成功生成本地代理后,調用WCF就會一直報這個錯誤。究其原因,就是因為生成代理類的屬性指定了反序列化的順序,而服務端我是沒有指定的。所以,先把WCF服務部署到IIS下,然后客戶端地址指向部署IISWCF服務,重新更新服務,再把配置文件中地址指向部署在JexusWCF服務即可。

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

[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請求的時候是有點問題。在這里還是要感謝宇內那么熱心的幫助我解決問題。

五、數據庫遷移

     數據庫的遷移遇到的問題不是很多,借助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>

六、地圖遷移

  由於地圖服務器是單獨一台,最終是用Perl + Apache來實現的,實現也挺簡單的,幾十行代碼,就是地圖引擎請求一個圖片路徑,將圖片輸出就可以了。最開始的時候,用的是Asp.net,部署在Jexus上,但是不知道為什么某些圖片始終輸出不出來,最終還是放棄了。

最后附上一張系統遷移后成功后的圖片:

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM