1. POJOをキャッシュに保存する必要があります。クラスは次のように定義されています
public class TestPOJO implements Serializable { private String testStatus; private String userPin; private String investor; private Date testQueryTime; private Date createTime; private String bizInfo; private Date otherTime; private BigDecimal userAmount; private BigDecimal userRate; private BigDecimal applyAmount; private String type; private String checkTime; private String preTestStatus; public Object[] toValueArray(){ Object[] array = {testStatus, userPin, investor, testQueryTime, createTime, bizInfo, otherTime, userAmount, userRate, applyAmount, type, checkTime, preTestStatus}; return array; } public CreditRecord fromValueArray(Object[] valueArray){ //具体的数据类型会丢失,需要做处理 } }
2. 次の例をテストデータとして使用します
TestPOJO pojo = new TestPOJO(); pojo.setApplyAmount(new BigDecimal("200.11")); pojo.setBizInfo("XX"); pojo.setUserAmount(new BigDecimal("1000.00")); pojo.setTestStatus("SUCCESS"); pojo.setCheckTime("2023-02-02"); pojo.setInvestor("ABCD"); pojo.setUserRate(new BigDecimal("0.002")); pojo.setTestQueryTime(new Date()); pojo.setOtherTime(new Date()); pojo.setPreTestStatus("PROCESSING"); pojo.setUserPin("ABCDEFGHIJ"); pojo.setType("Y");
System.out.println(JSON.toJSONString(pojo).length());
JSON を使用して直接シリアル化して出力する length=284**、**この方法は最も簡単な方法です。これは最も一般的に使用される方法でもあります。具体的なデータは次のとおりです:
{"applyAmount":200.11,"bizInfo":"XX","checkTime":"2023-02-02","投資家":"ABCD ","otherTime":"2023-04-10 17:45:17.717","preCheckStatus":"PROCESSING","testQueryTime":"2023-04-10 17:45:17.717"," testStatus":"SUCCESS ","type":"Y","userAmount":1000.00,"userPin":"ABCDEFGHIJ","userRate":0.002}
上記には多くのものが含まれていることがわかりました。属性名を含む無駄なデータは保存する必要はありません。
System.out.println(JSON.toJSONString(pojo.toValueArray()).length());
オブジェクト構造の代わりに配列構造を選択すると、属性名が削除され、length=144 が印刷されます。データサイズが 50% 削減されました。具体的なデータは次のとおりです:
["SUCCESS","ABCDEFGHIJ","ABCD","2023-04-10 17: 45:17.717",null,"XX"," 2023-04-10 17:45:17.717",1000.00,0.002,200.11,"Y","2023-02-02","処理中"]
null を格納する必要がないことがわかりました。時刻形式は文字列にシリアル化されます。不当なシリアル化の結果はデータの拡張につながるため、より適切なシリアル化ツールを選択する必要があります。
//我们仍然选取JSON格式,但使用了第三方序列化工具 System.out.println(new ObjectMapper(new MessagePackFactory()).writeValueAsBytes(pojo.toValueArray()).length);
より優れたシリアル化ツールを選択して、フィールド圧縮と適切なデータ形式を実現します。print** length=92、スペースが削減されます。前のステップと比較して 40% 増加しました。
これはバイナリ データです。Redis はバイナリで操作する必要があります。バイナリを文字列に変換した後、次のように出力します:
��SUCCESS�ABCDEFGHIJ�ABCD� � j�6� �XX� �j�6� �?`bM����@i � �Q�Y�2023-02-02�PROCESSING
このアイデアに従ってさらに掘り下げて、データ型を手動で選択することで、より極端な最適化効果を達成できることがわかりました。より小さいデータ型を使用することを選択すると、さらに改善が得られます。
上記の使用例では、testStatus、preCheckStatus、investor の 3 つのフィールドは実際には列挙文字列型です。文字列の代わりにデータ型 (byte や int など) を使用すると、スペースをさらに節約できます。 checkTime を表す文字列の代わりに Long 型を使用すると、シリアル化ツールが出力するバイト数が少なくなります。
public Object[] toValueArray(){ Object[] array = {toInt(testStatus), userPin, toInt(investor), testQueryTime, createTime, bizInfo, otherTime, userAmount, userRate, applyAmount, type, toLong(checkTime), toInt(preTestStatus)}; return array; }
手動調整後、文字列型の代わりに小さなデータ型が使用され、印刷されますlength=69
上記の点に加えて、より小さなボリュームを取得するために ZIP 圧縮の使用を検討することもできます。コンテンツが大きい場合や繰り返しが多い場合、ZIP 圧縮の効果は明らかです。ストレージがコンテンツの場合、コンテンツは配列ですおそらく ZIP 圧縮での使用に適しています。
30 バイト未満のファイルの場合、ZIP 圧縮によってファイル サイズが増加する可能性がありますが、必ずしもファイル サイズが減少するとは限りません。繰り返しの少ないコンテンツの場合、大幅な改善は得られません。そしてCPUのオーバーヘッドも発生します。
上記の最適化後、ZIP 圧縮は必須のオプションではなくなり、ZIP 圧縮の効果を判断するには実際のデータに基づくテストが必要になります。
上記の改善手順は最適化のアイデアを反映していますが、逆シリアル化プロセスにより型の損失が発生し、処理がさらに面倒になるため、逆シリアル化の問題も考慮する必要があります。
キャッシュ オブジェクトが事前に定義されている場合、各フィールドを手動で完全に処理できるため、実際の戦闘では、上記の目的を達成し、洗練された制御を実現し、最適な圧縮を実現するために、手動シリアル化を使用することをお勧めします。効果があり、パフォーマンスのオーバーヘッドが最小限に抑えられます。
次の msgpack 実装コードを参照できます。以下はテスト コードです。より優れた Packer および UnPacker ツールを自分でパッケージ化してください:
<dependency> <groupId>org.msgpack</groupId> <artifactId>msgpack-core</artifactId> <version>0.9.3</version> </dependency>
public byte[] toByteArray() throws Exception { MessageBufferPacker packer = MessagePack.newDefaultBufferPacker(); toByteArray(packer); packer.close(); return packer.toByteArray(); } public void toByteArray(MessageBufferPacker packer) throws Exception { if (testStatus == null) { packer.packNil(); }else{ packer.packString(testStatus); } if (userPin == null) { packer.packNil(); }else{ packer.packString(userPin); } if (investor == null) { packer.packNil(); }else{ packer.packString(investor); } if (testQueryTime == null) { packer.packNil(); }else{ packer.packLong(testQueryTime.getTime()); } if (createTime == null) { packer.packNil(); }else{ packer.packLong(createTime.getTime()); } if (bizInfo == null) { packer.packNil(); }else{ packer.packString(bizInfo); } if (otherTime == null) { packer.packNil(); }else{ packer.packLong(otherTime.getTime()); } if (userAmount == null) { packer.packNil(); }else{ packer.packString(userAmount.toString()); } if (userRate == null) { packer.packNil(); }else{ packer.packString(userRate.toString()); } if (applyAmount == null) { packer.packNil(); }else{ packer.packString(applyAmount.toString()); } if (type == null) { packer.packNil(); }else{ packer.packString(type); } if (checkTime == null) { packer.packNil(); }else{ packer.packString(checkTime); } if (preTestStatus == null) { packer.packNil(); }else{ packer.packString(preTestStatus); } } public void fromByteArray(byte[] byteArray) throws Exception { MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(byteArray); fromByteArray(unpacker); unpacker.close(); } public void fromByteArray(MessageUnpacker unpacker) throws Exception { if (!unpacker.tryUnpackNil()){ this.setTestStatus(unpacker.unpackString()); } if (!unpacker.tryUnpackNil()){ this.setUserPin(unpacker.unpackString()); } if (!unpacker.tryUnpackNil()){ this.setInvestor(unpacker.unpackString()); } if (!unpacker.tryUnpackNil()){ this.setTestQueryTime(new Date(unpacker.unpackLong())); } if (!unpacker.tryUnpackNil()){ this.setCreateTime(new Date(unpacker.unpackLong())); } if (!unpacker.tryUnpackNil()){ this.setBizInfo(unpacker.unpackString()); } if (!unpacker.tryUnpackNil()){ this.setOtherTime(new Date(unpacker.unpackLong())); } if (!unpacker.tryUnpackNil()){ this.setUserAmount(new BigDecimal(unpacker.unpackString())); } if (!unpacker.tryUnpackNil()){ this.setUserRate(new BigDecimal(unpacker.unpackString())); } if (!unpacker.tryUnpackNil()){ this.setApplyAmount(new BigDecimal(unpacker.unpackString())); } if (!unpacker.tryUnpackNil()){ this.setType(unpacker.unpackString()); } if (!unpacker.tryUnpackNil()){ this.setCheckTime(unpacker.unpackString()); } if (!unpacker.tryUnpackNil()){ this.setPreTestStatus(unpacker.unpackString()); } }
2 億ユーザーのデータを保存すると仮定します。各ユーザーには 40 個のフィールドが含まれます。フィールド キーの長さは 6 バイトで、フィールドは個別に管理されます。
通常の状況では、ハッシュ構造を考えますが、ハッシュ構造にはキー情報が格納されるため、追加のリソースが占有されます。フィールドのキーは不要なデータです。上記の考え方によれば、代わりにリストを使用できます。ハッシュ構造の。
Redis 公式ツールのテストによると、リスト構造の使用には 144G のスペースが必要ですが、ハッシュ構造の使用には 245G のスペースが必要です** (属性の 50% 以上が空の場合は、これはまだ適用可能です)* *
上記の例では、数行の簡単なコードで非常に簡単な措置をいくつか講じました。これにより、スペースをさらに削減できます。データ量が比較的大きい場合、大規模で高いパフォーマンス要件が必要なシナリオでは、これを強くお勧めします。 :
• オブジェクトの代わりに配列を使用します (多数のフィールドが空の場合は、シリアル化ツールを使用して null を圧縮する必要があります)
• より適切なシリアル化ツールを使用します
•より小さいデータ型を使用します
• ZIP 圧縮の使用を検討してください
• ハッシュ構造の代わりにリストを使用します (多数のフィールドが空の場合は、テストと比較が必要です)
以上がRedis キャッシュスペースを最適化する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。