溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java性能優(yōu)化中如何進(jìn)行壓縮

發(fā)布時(shí)間:2021-10-20 09:24:39 來(lái)源:億速云 閱讀:197 作者:柒染 欄目:大數(shù)據(jù)

Java性能優(yōu)化中如何進(jìn)行壓縮,相信很多沒(méi)有經(jīng)驗(yàn)的人對(duì)此束手無(wú)策,為此本文總結(jié)了問(wèn)題出現(xiàn)的原因和解決方法,通過(guò)這篇文章希望你能解決這個(gè)問(wèn)題。

 壓縮

在微服務(wù)調(diào)用,如果需要傳入的內(nèi)容過(guò)長(zhǎng),壓縮是個(gè)不錯(cuò)的辦法,能提高傳輸?shù)乃俣?。壓縮有很多方法,一種方法是在傳輸對(duì)象的屬性名字上做調(diào)整,盡量減少傳輸報(bào)文大小,這比較適合傳輸?shù)氖荍SON或者XML,比如

public class OrderRequest{
  private String orderId;
  private String userId;

}

如果使用JSON傳輸,內(nèi)容是

{"orderId":xxx,"userId":yyyyy}

可以調(diào)整為

public class OrderRequest{
  private String oid;
  private String uid;
}

使用JSON傳輸 {"oid":xxx,"uid":yyyyy},這種調(diào)整,顯然傳輸報(bào)文大小體積小一點(diǎn)。也可以對(duì)傳輸對(duì)象的一些字段做合并,比如“訂單狀態(tài)“,"用戶狀態(tài)","測(cè)試訂單"合并成一個(gè)int類型,通過(guò)“位“來(lái)區(qū)分狀態(tài)

public class OrderRequest{
  //用戶狀態(tài)
  private int userStatus;
  //訂單狀態(tài)
  private int orderStatus;
  //測(cè)試訂單
  private int testFlag
}

改成如下,需要通過(guò)位運(yùn)算獲取訂單的各個(gè)狀態(tài)

public class OrderRequest {
	/**
	 * 0位表示是否測(cè)試訂單,1-4位節(jié)表示用戶狀態(tài),5-8位表示訂單狀態(tài)
	 */
	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本來(lái)需要3個(gè)int類型,總計(jì)12個(gè)字節(jié)來(lái)保存的訂單狀態(tài),現(xiàn)在只需要4個(gè)字節(jié)保存即可。如果有更多的狀態(tài),也可以用s值的剩下的位來(lái)表示。比如,訂單新增一個(gè)狀態(tài)表示是否是包含大件,可以用第9位表示

public boolean isLargeProduct(){
   return (status>>9&0b1)==1;
}

如果s值是0b1_0100_0110_1(對(duì)應(yīng)的10進(jìn)制653),那么isTest返回true,getUerStatus返回6,getOrderStatus返回4,isLargeProduct返回true

還有一種壓縮方法是在傳輸協(xié)議上進(jìn)行壓縮,比如JSON就比XML更加節(jié)省,使用MessagePack又比JSON更加節(jié)省空間,關(guān)于MessagePack用法,會(huì)在第5章用一節(jié)詳細(xì)介紹。

在傳輸內(nèi)容過(guò)多的時(shí)候,可以考慮對(duì)內(nèi)容進(jìn)行壓縮,對(duì)內(nèi)容進(jìn)行壓縮再傳送有如下好處

  • 壓縮后減少網(wǎng)絡(luò)傳送的字節(jié),節(jié)約了帶寬,網(wǎng)絡(luò)可以同時(shí)傳送的內(nèi)容更多了

  • 相比于壓縮耗時(shí),網(wǎng)絡(luò)傳送更加耗時(shí)。尤其是現(xiàn)在的分布式系統(tǒng),服務(wù)器非常便宜,可以無(wú)限擴(kuò)展,從數(shù)十臺(tái)服務(wù)器到數(shù)萬(wàn)臺(tái)服務(wù)都可以,然而帶寬有限且價(jià)格不菲,有些企業(yè)專網(wǎng)帶寬只有1M,非常小。

壓縮有各種算法,會(huì)輸出不同的壓縮比的內(nèi)容,以及壓縮耗時(shí)也不一樣,本節(jié)選取zip,針對(duì)5K,20K,100k的做一個(gè)性能測(cè)試。一般來(lái)說(shuō),壓縮比越大,越耗時(shí)。在實(shí)際分布式系統(tǒng)調(diào)用,需要根據(jù)業(yè)務(wù)需求,確定采用什么樣的壓縮算法。

壓縮會(huì)使用JDK自帶的zip包中的Deflater類進(jìn)行壓縮,提供了最快壓縮BEST_SPEED(值是1),最大壓縮比BEST_COMPRESSION(值是9),還有默認(rèn)壓縮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);
		//壓縮內(nèi)容
		compressor.setInput(input
		//壓縮結(jié)束
		compressor.finish();
		//獲取壓縮內(nèi)容
		ByteArrayOutputStream bao = new ByteArrayOutputStream();
		//一個(gè)緩沖
		byte[] readBuffer = new byte[1024];
		int readCount = 0;
		//如果壓縮內(nèi)容,則循環(huán)
		while (!compressor.finished()) {
			readCount = compressor.deflate(readBuffer);
			if (readCount > 0) {
				bao.write(readBuffer, 0, readCount);
			}
		}

		compressor.end();
		return bao.toByteArray();
	}

可以測(cè)試一個(gè)100k報(bào)文,對(duì)于三種壓縮比,有如下數(shù)據(jù),說(shuō)明ZIP的默認(rèn)壓縮級(jí)別已經(jīng)足夠好 DEFAULT_COMPRESSION 壓縮后是34.8K BEST_SPEED 壓縮是39K BEST_COMPRESSION 壓縮后是34.7K

為了測(cè)試壓縮性能,通過(guò)Content工具類分別生成5K,20K,100K報(bào)文供測(cè)試,并且分別測(cè)試默認(rèn)壓縮,最快壓縮和最好壓縮。

// ZipTest.java
byte[] k5 = null;
byte[] k20 = null;
byte[] k100 = null;
//默認(rèn),最快,最好壓縮
@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測(cè)試結(jié)果如下??梢钥吹郊词?0K報(bào)文內(nèi)容,壓縮的速度還是非常快的。在不到1毫秒。100K報(bào)文,則需要較長(zhǎng)時(shí)間,默認(rèn)壓縮(-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

這個(gè)測(cè)試選用的是一篇文章作為壓縮內(nèi)容,你需要根據(jù)你的業(yè)務(wù)情況,用真實(shí)的報(bào)文來(lái)做壓縮測(cè)試,事實(shí)上,如果是XML或者JSON報(bào)文,有著非常大的壓縮比。

本節(jié)選擇了zip壓縮方式,還有其他可選方式,比如gzip,bzip2,7z等等,可以使用開(kāi)源庫(kù)Apache Commons Compress進(jìn)行壓縮,在筆者測(cè)試后,發(fā)現(xiàn)zip還是一種壓縮比和性能都比較好的方式。7z具有最大的壓縮比,但壓縮時(shí)長(zhǎng)超過(guò)百毫秒,在實(shí)時(shí)的業(yè)務(wù)系統(tǒng)中是不可接受的。

對(duì)于解壓來(lái)說(shuō),無(wú)論采用何種壓縮方式,何種壓縮級(jí)別,解壓需要的時(shí)間都是非常少的。

看完上述內(nèi)容,你們掌握J(rèn)ava性能優(yōu)化中如何進(jìn)行壓縮的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI