您好,登錄后才能下訂單哦!
Java性能優化中如何進行壓縮,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
在微服務調用,如果需要傳入的內容過長,壓縮是個不錯的辦法,能提高傳輸的速度。壓縮有很多方法,一種方法是在傳輸對象的屬性名字上做調整,盡量減少傳輸報文大小,這比較適合傳輸的是JSON或者XML,比如
public class OrderRequest{ private String orderId; private String userId; }
如果使用JSON傳輸,內容是
{"orderId":xxx,"userId":yyyyy}
可以調整為
public class OrderRequest{ private String oid; private String uid; }
使用JSON傳輸 {"oid":xxx,"uid":yyyyy},這種調整,顯然傳輸報文大小體積小一點。也可以對傳輸對象的一些字段做合并,比如“訂單狀態“,"用戶狀態","測試訂單"合并成一個int類型,通過“位“來區分狀態
public class OrderRequest{ //用戶狀態 private int userStatus; //訂單狀態 private int orderStatus; //測試訂單 private int testFlag }
改成如下,需要通過位運算獲取訂單的各個狀態
public class OrderRequest { /** * 0位表示是否測試訂單,1-4位節表示用戶狀態,5-8位表示訂單狀態 */ int s; public boolean isTest(){ //取出第1位的值 return (status&0b1)==1; } public int getUserStatus(){ // 右移1,取出1-4位的值 return (status>>1&0b1111); } public int getOrderStatus(){ //右移5,取出5-8位的值 return (status>>5&0b1111); } }
這樣,OrderRequest本來需要3個int類型,總計12個字節來保存的訂單狀態,現在只需要4個字節保存即可。如果有更多的狀態,也可以用s值的剩下的位來表示。比如,訂單新增一個狀態表示是否是包含大件,可以用第9位表示
public boolean isLargeProduct(){ return (status>>9&0b1)==1; }
如果s值是0b1_0100_0110_1(對應的10進制653),那么isTest返回true,getUerStatus返回6,getOrderStatus返回4,isLargeProduct返回true
還有一種壓縮方法是在傳輸協議上進行壓縮,比如JSON就比XML更加節省,使用MessagePack又比JSON更加節省空間,關于MessagePack用法,會在第5章用一節詳細介紹。
在傳輸內容過多的時候,可以考慮對內容進行壓縮,對內容進行壓縮再傳送有如下好處
壓縮后減少網絡傳送的字節,節約了帶寬,網絡可以同時傳送的內容更多了
相比于壓縮耗時,網絡傳送更加耗時。尤其是現在的分布式系統,服務器非常便宜,可以無限擴展,從數十臺服務器到數萬臺服務都可以,然而帶寬有限且價格不菲,有些企業專網帶寬只有1M,非常小。
壓縮有各種算法,會輸出不同的壓縮比的內容,以及壓縮耗時也不一樣,本節選取zip,針對5K,20K,100k的做一個性能測試。一般來說,壓縮比越大,越耗時。在實際分布式系統調用,需要根據業務需求,確定采用什么樣的壓縮算法。
壓縮會使用JDK自帶的zip包中的Deflater類進行壓縮,提供了最快壓縮BEST_SPEED(值是1),最大壓縮比BEST_COMPRESSION(值是9),還有默認壓縮DEFAULT_COMPRESSION(值是-1)
//ZipUtil.java public static byte[] zip(byte[] bs) throws IOException { return compress(bs,DEFAULT_COMPRESSION); } public static byte[] compress(byte[] input, int compressionLevel ) throws IOException { //zip壓縮 Deflater compressor = new Deflater(compressionLevel, false); //壓縮內容 compressor.setInput(input //壓縮結束 compressor.finish(); //獲取壓縮內容 ByteArrayOutputStream bao = new ByteArrayOutputStream(); //一個緩沖 byte[] readBuffer = new byte[1024]; int readCount = 0; //如果壓縮內容,則循環 while (!compressor.finished()) { readCount = compressor.deflate(readBuffer); if (readCount > 0) { bao.write(readBuffer, 0, readCount); } } compressor.end(); return bao.toByteArray(); }
可以測試一個100k報文,對于三種壓縮比,有如下數據,說明ZIP的默認壓縮級別已經足夠好 DEFAULT_COMPRESSION 壓縮后是34.8K BEST_SPEED 壓縮是39K BEST_COMPRESSION 壓縮后是34.7K
為了測試壓縮性能,通過Content工具類分別生成5K,20K,100K報文供測試,并且分別測試默認壓縮,最快壓縮和最好壓縮。
// ZipTest.java byte[] k5 = null; byte[] k20 = null; byte[] k100 = null; //默認,最快,最好壓縮 @Param({"-1", "1", "9"}) int level; @Setup public void init() { Content content = new Content(); this.k5 = content.genContentBySize(1000 * 5); this.k20 = content.genContentBySize(1000 * 20); this.k100 = content.genContentBySize(1000 * 100); } @Benchmark public byte[] k5() throws IOException { return ZipUtil.compress(k5, level); } @Benchmark public byte[] k20() throws IOException { return ZipUtil.compress(k20, level); } @Benchmark public byte[] k100() throws IOException { return ZipUtil.compress(k100, level); }
JMH測試結果如下。可以看到即使20K報文內容,壓縮的速度還是非常快的。在不到1毫秒。100K報文,則需要較長時間,默認壓縮(-1)需要4毫秒左右。
Benchmark (level) Score Score error Units c.i.c.c.ZipTest.k100 -1 4.467 0.233 ms/op c.i.c.c.ZipTest.k100 1 1.773 0.097 ms/op c.i.c.c.ZipTest.k100 9 5.028 0.152 ms/op c.i.c.c.ZipTest.k20 -1 0.571 0.016 ms/op c.i.c.c.ZipTest.k20 1 0.310 0.010 ms/op c.i.c.c.ZipTest.k20 9 0.592 0.023 ms/op c.i.c.c.ZipTest.k5 -1 0.157 0.008 ms/op c.i.c.c.ZipTest.k5 1 0.112 0.005 ms/op c.i.c.c.ZipTest.k5 9 0.151 0.003 ms/op
這個測試選用的是一篇文章作為壓縮內容,你需要根據你的業務情況,用真實的報文來做壓縮測試,事實上,如果是XML或者JSON報文,有著非常大的壓縮比。
本節選擇了zip壓縮方式,還有其他可選方式,比如gzip,bzip2,7z等等,可以使用開源庫Apache Commons Compress進行壓縮,在筆者測試后,發現zip還是一種壓縮比和性能都比較好的方式。7z具有最大的壓縮比,但壓縮時長超過百毫秒,在實時的業務系統中是不可接受的。
對于解壓來說,無論采用何種壓縮方式,何種壓縮級別,解壓需要的時間都是非常少的。
看完上述內容,你們掌握Java性能優化中如何進行壓縮的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。