早先我們觀察過WCF HTTP vs TCP的傳輸量差異,該測試呼叫GetData()作業傳入數字接回字串,並不算真的用到WCF的DataContract/DataMember序列化功能,故這次改聚焦在物件資料的序列化上,再做一次比較。

我小幅改寫Visual Studio WCF專案範本的CompositeType,增加一個IntValue。

    [DataContract]
    public class CompositeType
    {
        bool boolValue = true;
        string stringValue = "Hello ";
        int intValue = 1;
 
        [DataMember]
        public bool BoolValue
        {
            get { return boolValue; }
            set { boolValue = value; }
        }
 
        [DataMember]
        public string StringValue
        {
            get { return stringValue; }
            set { stringValue = value; }
        }
 
        [DataMember]
        public int IntValue
        {
            get { return intValue; }
            set { intValue = value; }
        }
    }

GetDataUsingDataContract()也做一點改寫,傳回值改成CompositeType[],傳回資料筆數由傳入的CompositeType.IntValue決定,藉此彈性控制傳回結果筆數,以觀察資料筆數多寡對資料量的影響。

        public CompositeType[] GetDataUsingDataContract(CompositeType composite)
        {
            if (composite == null)
            {
                throw new ArgumentNullException("composite");
            }
            var res = new List<CompositeType>();
            for (var i = 0; i < composite.IntValue; i++)
                res.Add(new CompositeType()
                {
                    BoolValue = composite.BoolValue,
                    StringValue = "Item" + i,
                    IntValue = i
                });
            return res.ToArray();
        }

Client端則修改如下,改呼叫GetDataUsingDataContract(),透過IntValue要求Server傳回1、16、64、128或256筆結果,取得結果後加總各筆資料的IntValue並檢視最後一筆的StringValue,簡單驗證資料正確性。

        static void Main(string[] args)
        {
            string[] bindingTypes = new string[] {
                "BasicHttpBinding_IService1",
                "NetTcpBinding_IService1"
            };
            foreach (var bindingType in bindingTypes)
            {
                var tsc = new WcfWas.Service1Client(bindingType);
                var compData = new WcfWas.CompositeType()
                {
                    BoolValue = true
                };
                var counts = new int[] {1, 16, 64, 128, 256};
                for (int i = 0; i < counts.Length; i++)
                {
                    compData.IntValue = counts[i];
                    var res = tsc.GetDataUsingDataContract(compData);
                    var sum = res.Sum(o => o.IntValue);
                    var txt = res.Last().StringValue;
                    Console.WriteLine("Items Count={0}, Sum={1}, String={2}", 
                        res.Length, sum, txt);
                }
            }
            Console.Read();
        }

執行結果如下,顯示內容沒什麼意義,期間的資料傳輸量才是重點。

Items Count=1, Sum=0, String=Item0
Items Count=16, Sum=120, String=Item15
Items Count=64, Sum=2016, String=Item63
Items Count=128, Sum=8128, String=Item127
Items Count=256, Sum=32640, String=Item255
Items Count=1, Sum=0, String=Item0
Items Count=16, Sum=120, String=Item15
Items Count=64, Sum=2016, String=Item63
Items Count=128, Sum=8128, String=Item127
Items Count=256, Sum=32640, String=Item255

所以我們開啟MNM,觀察HTTP及TCP傳輸的封包記錄如下。黃底部分是每次Server用來回傳結果的封包,旁邊已加註該次傳回資料筆數方便對照。

BasicHttpBinding

NetTcpBinding

整理結果如下,中間兩欄的數字為HTTP及TCP傳回不同結果筆數產生資料量(Bytes),最後一欄則為TCP資料量除以HTTP資料量的比例。

數字有點可疑,BasicHttpBinding使用XML序列化,NetTcpBinding採二進位序列化,但差距比想像的小很多,且筆數愈多,差距愈小,在256筆時,資料量比例約為10:8,與直覺出入甚大。莫非與HTTP壓縮有關?檢視封包內容,果然看到SOAP XML被IIS壓縮,實際上傳送的不是XML,而是被壓縮過看似亂碼的資料。

為觀察未壓縮的原始資料量,在IIS關閉動態內容壓縮:

重新測試一次,這回可在封包觀察到SOAP XML的模樣,很肥!

而用XML傳256筆資料要花35,118 bytes。

重新統計IIS未壓縮模式下的SOAP XML傳輸,除了單筆資料外,不管筆數多寡,TCP資料量固定維持SOAP XML的15%,符合我們的認知。

實務上,IIS會啟用動態壓縮,最後的實驗純屬好奇並非常態,第一次做的統計才接近真實狀況。也就是說,在IIS壓縮加持下,HTTP+SOAP XML的資料量膨脹不如想像嚴重(例如:256筆時僅多21%),但每次傳輸耗用較多封包數,資料量較大仍是事實,基於效能考量,Intranet的純Windows應用仍應優先考慮TCP。


Comments

Be the first to post a comment

Post a comment