由GZipStream的压缩,減少Web Service的传输量
2009-11-26 08:48
274 查看
不知道有多少人有遇到跟我一樣的問題,就是Web Service的資料回傳量太大了,如果都是走區域網路的話,除非量很大,不然還感覺不太出來,可是,如果是透過ADSL的頻寬的話,那就很驚人了,以30MB的資料量來說,透過2M/512K的網路上傳,加上網路品質的損耗以65%來看,也大概要花738秒左右來上傳. (30*1024)/((512*0.65)/8)=738.46. 這樣的時間,看起來很嚇人,何況在上傳滿載時,下載的頻寬可能剩40%不到,如果今天能壓縮這資料量,讓資料量剩25%左右,那上傳時間就只要185秒左右,這樣的差異就很大了,如果今天我們採用的是n-tier架構,Client是透過Web Service在要資料,那要怎麼去壓縮這傳輸過程中的資料? 這時就可以拿GZipStream出來用了.
起初,GZipStream只是被我拿來當檔案壓縮用的,剛好這段時間遇到公司ERP系統效能調校,突然產生了一個想法,如果我能拿它來壓縮資料,那傳輸的資料量不就小很多,尤其是XML的文字檔,效果一定更明顯,就在這個念頭下,著手開始寫了測試的程式,在這裡,我做了兩種不同的做法,一個是純壓縮,不Serialize,另一種做法是壓縮與Serialize,而這兩種做法,是會產生些微的資料量差異.
在提到程式內容之前,先說明這做法所造成的資料量差異,詳見下表 :
接下來,就是程式碼部份,分兩個部份說明:
1 .純壓縮 :
WebService Side :
Client Side :
2. 壓縮+Serialize
Web Service Side :
Client Side :
2008/04/29 補充 :
最近有網友看到這篇文章,有些問題問我朋友,而朋友再來轉問我這個問題(真巧,網友問我朋友,我朋友再來問我),而提出的問題是,壓縮跟解壓是否很耗用CPU的效能? 答案是,不可能不用到CPU的效能,但它也不致於到"很耗用"的地步. 而這耗用率只能視設備狀況來判斷,以我的環境來說,Client端的電腦是P4 3GHT, 上面的這個例子跑的時候有個瞬間最高47%,不到一秒的時間,如果是未壓縮版的,瞬間最高為37%左右,所以大概多個10%吧.
或許有人還是有疑慮怎麼可以增加CPU的Loading呢,這樣就不好了,這時我們就要換個角度來思考這個問題了,"效能成本"所在為何,我們的Bottleneck在那.CPU在科技的進步下,雙核四核的都推出了,CPU的效能是快速的在倍增中,而我們的網路呢? 絕大多數區域還在100MB,部份Server與Server是1G在連,而ADSL呢? 10M/1M或者是只能2M/512K,因為申請不到更快的頻寬,如果要更快,每月的費用就更高, 注意囉,上傳是1MB或512K哦,而且是多人共用的,所以就目前國內的網路環境來看,ADSL要到100M/100M,似乎還要很長的一段時間,而這段時間的CPU,也不知道已經成長到幾核心了,兩者之間怎麼取捨,就看大家的看法囉.
2008/5/30 補充
因為一些朋友對這個方式感到有興趣,也在網路上找了一些文章,可是卻又發現了一些疑問,到底這個壓縮技術能用在什麼樣的情況下. 其中一位朋友傳給了我一個網址.Net DataTable 大量資料壓縮加密實測,也是說明用壓縮的方式來減少流量,一些測試結果也很詳盡,有興趣的人建議參考,只是朋友在他的文章開頭的地方看到 [開發 Web 或分散式系統],這是否代表Web網站也可以用? 這個答案當然是沒用的,試想,我們在Web Server壓縮,Client端用IE或Firefox怎麼解壓縮,網頁是無法用Gzipstream的方式來解壓縮來減少Web Server到Client的資料量,能壓一定要能解才有用,所以就不用再去列出那些可以及那些不行了,畢竟這還關係的架構上的問題,所以應用的關鍵就是"能壓要能解才能用".
另一個問題就是選擇性的使用,壓縮的動作勢必用到系統的效能,如果全面性100%的採用壓縮,當使用者多,或操作頻率高時,資料量大,系統效能也會變的更加吃重,所以必需挑選幾個關鍵的傳輸來壓縮即可,不用連1K不到的資料量也在壓縮,除非Server很猛的,那就另當別論. 依我的情況,我會挑選幾個使用者的查詢作業來壓,依目前手頭上的分析資料來看,有個查詢作業使用頻率較高,資料量也是驚人,最高的資料量就一次高達33MB,平均起來跟其它作業比較,這作業的資料量佔了不小的比率,光這作業一天平均傳輸量650MB,壓縮後只剩162.5MB在傳,所以只壓縮這個作業的查詢動作,就可明顯的改善ADSL的頻寬瓶頸. 所以要視情況去選擇要壓縮的作業.
原文地址:http://www.dotblogs.com.tw/jeff-yeh/archive/2008/04/16/2932.aspx
起初,GZipStream只是被我拿來當檔案壓縮用的,剛好這段時間遇到公司ERP系統效能調校,突然產生了一個想法,如果我能拿它來壓縮資料,那傳輸的資料量不就小很多,尤其是XML的文字檔,效果一定更明顯,就在這個念頭下,著手開始寫了測試的程式,在這裡,我做了兩種不同的做法,一個是純壓縮,不Serialize,另一種做法是壓縮與Serialize,而這兩種做法,是會產生些微的資料量差異.
在提到程式內容之前,先說明這做法所造成的資料量差異,詳見下表 :
正常資料量 | 壓縮後 | 壓縮+Serialize |
18,368,067 Bytes | 4,755,570 Bytes | 4,445,278 Bytes |
17,937.57 Kb | 4,644.11 Kb | 4,341.09 Kb |
1 .純壓縮 :
WebService Side :
using System.IO; using System.IO.Compression; [WebMethod] public byte[] getZipData() { DataSet ds = LoadData().Copy(); MemoryStream unMS = new MemoryStream(); ds.WriteXml(unMS); byte[] bytes = unMS.ToArray(); int lenbyte = bytes.Length; MemoryStream compMs = new MemoryStream(); GZipStream compStream = new GZipStream(compMs, CompressionMode.Compress, true); compStream.Write(bytes, 0, lenbyte); compStream.Close(); unMS.Close(); compMs.Close(); byte[] zipData = compMs.ToArray(); return zipData; } private DataSet LoadData() {//產生測試資料用 DataSet ds = new DataSet(); DataTable dt = new DataTable("Test"); dt.Columns.Add("ProID",typeof(int)); dt.Columns.Add("ProName", typeof(string)); dt.Columns.Add("CreateTime", typeof(DateTime)); dt.Columns["ProID"].AutoIncrement = true; for (int i = 0; i < 100000; i++) { DataRow dr = dt.NewRow(); dr["ProName"] = Guid.NewGuid().ToString(); dr["CreateTime"] = DateTime.Now.ToString(); dt.Rows.Add(dr); } ds.Tables.Add(dt); ds.AcceptChanges(); return ds; }
Client Side :
using System.IO.Compression; using System.IO; private void btn_ZipGet_Click(object sender, EventArgs e) { try { WS.Service1 wss = new WSZipDemo.WS.Service1();//WebReference byte[] da = wss.getZipData(); MemoryStream input = new MemoryStream(); input.Write(da, 0, da.Length); input.Position = 0; GZipStream gzip = new GZipStream(input, CompressionMode.Decompress, true); MemoryStream output = new MemoryStream(); byte[] buff = new byte[4096]; int read = -1; read = gzip.Read(buff, 0, buff.Length); while (read > 0) { output.Write(buff, 0, read); read = gzip.Read(buff, 0, buff.Length); } gzip.Close(); byte[] rebytes = output.ToArray(); output.Close(); input.Close(); MemoryStream ms = new MemoryStream(rebytes); DataSet ds = new DataSet(); ds.ReadXml(ms); dataGridView1.DataSource = ds.Tables[0]; } catch (Exception ex) { MessageBox.Show(ex.Message); } }
2. 壓縮+Serialize
Web Service Side :
using System.IO; using System.IO.Compression; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; [WebMethod] public byte[] getZipData() { DataSet ds = LoadData().Copy(); ds.RemotingFormat = SerializationFormat.Binary; BinaryFormatter ser = new BinaryFormatter(); MemoryStream unMS = new MemoryStream(); ser.Serialize(unMS, ds); byte[] bytes = unMS.ToArray(); int lenbyte = bytes.Length; MemoryStream compMs = new MemoryStream(); GZipStream compStream = new GZipStream(compMs, CompressionMode.Compress, true); compStream.Write(bytes, 0, lenbyte); compStream.Close(); unMS.Close(); compMs.Close(); byte[] zipData = compMs.ToArray(); return zipData; } private DataSet LoadData() {//產生測試資料用 DataSet ds = new DataSet(); DataTable dt = new DataTable("Test"); dt.Columns.Add("ProID",typeof(int)); dt.Columns.Add("ProName", typeof(string)); dt.Columns.Add("CreateTime", typeof(DateTime)); dt.Columns["ProID"].AutoIncrement = true; for (int i = 0; i < 100000; i++) { DataRow dr = dt.NewRow(); dr["ProName"] = Guid.NewGuid().ToString(); dr["CreateTime"] = DateTime.Now.ToString(); dt.Rows.Add(dr); } ds.Tables.Add(dt); ds.AcceptChanges(); return ds; }
Client Side :
using System.IO.Compression; using System.IO; using System.Runtime.Serialization.Formatters.Binary; private void btn_ZipGet_Click(object sender, EventArgs e) { try { WS.Service1 wss = new WSZipDemo.WS.Service1();//WebReference byte[] da = wss.getZipData(); MemoryStream input = new MemoryStream(); input.Write(da, 0, da.Length); input.Position = 0; GZipStream gzip = new GZipStream(input, CompressionMode.Decompress, true); MemoryStream output = new MemoryStream(); byte[] buff = new byte[4096]; int read = -1; read = gzip.Read(buff, 0, buff.Length); while (read > 0) { output.Write(buff, 0, read); read = gzip.Read(buff, 0, buff.Length); } gzip.Close(); byte[] rebytes = output.ToArray(); output.Close(); input.Close(); MemoryStream ms = new MemoryStream(rebytes); BinaryFormatter bf = new BinaryFormatter(); object obj = bf.Deserialize(ms); DataSet ds = (DataSet)obj; dataGridView1.DataSource = ds.Tables[0]; } catch (Exception ex) { MessageBox.Show(ex.Message); } }
這兩種做法只是在部份的程式碼不一樣,但其它大多相同,如果是方法一,在WebService壓縮後Return,Client收到資料後,解壓縮即可,方法二則多了Serialize這部份,所以在WebService這邊,先Serialize,再壓縮,Client端收到後,先解壓縮再Deserialize. 不過,這個壓縮後的量,是很讓人滿意,如果在頻寬有限,又需要傳輸大量資料時,這個方法可以考慮看看. 因為這個是.Net 2.0以後才有的東西,公司現在的ERP還在.Net 1.0,所以.........殘念~
2008/04/29 補充 :
最近有網友看到這篇文章,有些問題問我朋友,而朋友再來轉問我這個問題(真巧,網友問我朋友,我朋友再來問我),而提出的問題是,壓縮跟解壓是否很耗用CPU的效能? 答案是,不可能不用到CPU的效能,但它也不致於到"很耗用"的地步. 而這耗用率只能視設備狀況來判斷,以我的環境來說,Client端的電腦是P4 3GHT, 上面的這個例子跑的時候有個瞬間最高47%,不到一秒的時間,如果是未壓縮版的,瞬間最高為37%左右,所以大概多個10%吧.
或許有人還是有疑慮怎麼可以增加CPU的Loading呢,這樣就不好了,這時我們就要換個角度來思考這個問題了,"效能成本"所在為何,我們的Bottleneck在那.CPU在科技的進步下,雙核四核的都推出了,CPU的效能是快速的在倍增中,而我們的網路呢? 絕大多數區域還在100MB,部份Server與Server是1G在連,而ADSL呢? 10M/1M或者是只能2M/512K,因為申請不到更快的頻寬,如果要更快,每月的費用就更高, 注意囉,上傳是1MB或512K哦,而且是多人共用的,所以就目前國內的網路環境來看,ADSL要到100M/100M,似乎還要很長的一段時間,而這段時間的CPU,也不知道已經成長到幾核心了,兩者之間怎麼取捨,就看大家的看法囉.
2008/5/30 補充
因為一些朋友對這個方式感到有興趣,也在網路上找了一些文章,可是卻又發現了一些疑問,到底這個壓縮技術能用在什麼樣的情況下. 其中一位朋友傳給了我一個網址.Net DataTable 大量資料壓縮加密實測,也是說明用壓縮的方式來減少流量,一些測試結果也很詳盡,有興趣的人建議參考,只是朋友在他的文章開頭的地方看到 [開發 Web 或分散式系統],這是否代表Web網站也可以用? 這個答案當然是沒用的,試想,我們在Web Server壓縮,Client端用IE或Firefox怎麼解壓縮,網頁是無法用Gzipstream的方式來解壓縮來減少Web Server到Client的資料量,能壓一定要能解才有用,所以就不用再去列出那些可以及那些不行了,畢竟這還關係的架構上的問題,所以應用的關鍵就是"能壓要能解才能用".
另一個問題就是選擇性的使用,壓縮的動作勢必用到系統的效能,如果全面性100%的採用壓縮,當使用者多,或操作頻率高時,資料量大,系統效能也會變的更加吃重,所以必需挑選幾個關鍵的傳輸來壓縮即可,不用連1K不到的資料量也在壓縮,除非Server很猛的,那就另當別論. 依我的情況,我會挑選幾個使用者的查詢作業來壓,依目前手頭上的分析資料來看,有個查詢作業使用頻率較高,資料量也是驚人,最高的資料量就一次高達33MB,平均起來跟其它作業比較,這作業的資料量佔了不小的比率,光這作業一天平均傳輸量650MB,壓縮後只剩162.5MB在傳,所以只壓縮這個作業的查詢動作,就可明顯的改善ADSL的頻寬瓶頸. 所以要視情況去選擇要壓縮的作業.
原文地址:http://www.dotblogs.com.tw/jeff-yeh/archive/2008/04/16/2932.aspx
相关文章推荐
- 藉由GZipStream的壓縮,來減少Web Service的傳輸量
- C# GZipStream 压缩 解压
- php解析 gzip压缩 chunked快传输
- IIS中启用Gzip压缩传输网页方法
- GZipStream实现压缩以及出现的问题
- Linux系统文件的网络传输、归档tar、压缩zip、gzip、bzip2、xz、gz、bz2
- Apache启用GZIP压缩网页传输方法
- 修改Apache配置文件开启gzip压缩传输
- android接口中json数据的传输中使用gzip压缩
- Windows 2003中如何启动IIS6的GZIP压缩网页传输(补充)
- php使用gzip压缩传输js和css文件的方法
- 服务器使用Gzip压缩数据,加快网络传输(Java 例子)
- Apache开启gzip压缩传输
- Apache启用GZIP压缩网页传输方法
- C# GZipStream 压缩和解压文件
- C#使用GZipStream压缩与解压字符串
- 【C#笔记】BZip2OutputStream和GZipStream压缩问题
- 开启gzip压缩传输
- 减小网络传输图片大小,使用gzip进行压缩
- 关于HTTP传输中gzip压缩的秘密探索分析