
本文作者以实际项目遇到的大key问题为线索,场景化地讲述对应的解决方案。
通过本文,您可以了解关于大key基础概念、影响以及遇到大key的具体解决手段,帮助您更好把控缓存的使用场景,从而提升软件系统的稳定性。
以下为本文目录:


(图一)
public String refreshHistoryData(){try {String key = "historyKey";Map<String, String> redisInfoMap= redisUtils.hGetAll(key);if (redisInfoMap.isEmpty()){return "查询缓存无数据";}for (Map.Entry<String, String> entry : redisInfoMap.entrySet()) {String redisVal = entry.getValue();String filedKey = entry.getKey();String newDataRedisKey = "newDataKey"+filedKey;redisUtils.set(newDataRedisKey,redisVal);}return "success";}catch (Exception e){LOG.error("refreshHistoryData 异常:",e);}return "failed";}
public enum CacheKeyConstant {/*** 订单基础缓存key*/REDIS_ORDER_BASE_INFO("ORDER_BASE_INFO"),/*** 订单商品缓存key*/ORDER_SUB_INFO("ORDER_SUB_INFO"),/*** 订单预售信息缓存key*/ORDER_PRESALE_INFO("ORDER_PRESALE_INFO"),/*** 订单履约信息缓存key*/ORDER_PREMISE_INFO("ORDER_PREMISE_INFO"),/*** 订单发票信息缓存key*/ORDER_INVOICE_INFO("ORDER_INVOICE_INFO"),/*** 订单轨迹信息缓存key*/ORDER_TRACK_INFO("ORDER_TRACK_INFO"),/*** 订单详细费用信息缓存key*/ORDER_FEE_INFO("ORDER_FEE_INFO"),;/*** 前缀*/private String prefix;/*** 项目统一前缀*/public static final String COMMON_PREFIX = "XXX";CacheKeyConstant(String prefix){this.prefix = prefix;}public String getPrefix(String subKey) {if(StringUtil.isNotEmpty(subKey)){return COMMON_PREFIX + prefix + "_" + subKey;}return COMMON_PREFIX + prefix;}public String getPrefix() {return COMMON_PREFIX + prefix;}}
/*** @description 刷新订单到缓存* @param order 订单信息*/public boolean refreshOrderToCache(Order order){if(order == null || order.getOrderId() == null){return ;}String orderId = order.getOrderId().toString();//设置存储缓存数据Map<String,String> cacheOrderMap = new HashMap<>(16);cacheOrderMap.put(CacheKeyConstant.ORDER_BASE_INFO.getPrefix(orderId), JSON.toJSONString(buildBaseOrderVo(order)));cacheOrderMap.put(CacheKeyConstant.ORDER_SUB_INFO.getPrefix(orderId), JSON.toJSONString(order.getCustomerOrderSubs()));cacheOrderMap.put(CacheKeyConstant.ORDER_PRESALE_INFO.getPrefix(orderId), JSON.toJSONString(order.getPresaleOrderData()));cacheOrderMap.put(CacheKeyConstant.ORDER_INVOICE_INFO.getPrefix(orderId), JSON.toJSONString(order.getOrderInvoice()));cacheOrderMap.put(CacheKeyConstant.ORDER_TRACK_INFO.getPrefix(orderId), JSON.toJSONString(order.getOrderTrackInfo()));cacheOrderMap.put(CacheKeyConstant.ORDER_PREMISE_INFO.getPrefix(orderId), JSON.toJSONString( order.getPresaleOrderData()));cacheOrderMap.put(CacheKeyConstant.ORDER_FEE_INFO.getPrefix(orderId), JSON.toJSONString(order.getOrderFeeVo()));superRedisUtils.mSetString(cacheOrderMap);}
/*** @description 通过订单号获取缓存数据* @param orderId 订单号* @return Order 订单实体信息*/public Order getOrderFromCache(String orderId){if(StringUtils.isBlank(orderId)){return null;}//定义查询缓存集合keyList<String> queryOrderKey = Arrays.asList(CacheKeyConstant.ORDER_BASE_INFO.getPrefix(orderId),CacheKeyConstant.ORDER_SUB_INFO.getPrefix(orderId),CacheKeyConstant.ORDER_PRESALE_INFO.getPrefix(orderId),CacheKeyConstant.ORDER_INVOICE_INFO.getPrefix(orderId),CacheKeyConstant.ORDER_TRACK_INFO.getPrefix(orderId),CacheKeyConstant.ORDER_PREMISE_INFO.getPrefix(orderId),CacheKeyConstant.ORDER_FEE_INFO.getPrefix(orderId));//查询结果List<String> result = redisUtils.mGet(queryOrderKey);//基础信息if(CollectionUtils.isEmpty(result)){return null;}String[] resultInfo = result.toArray(new String[0]);//基础信息if(StringUtils.isBlank(resultInfo[0])){return null;}BaseOrderVo baseOrderVo = JSON.parseObject(resultInfo[0],BaseOrderVo.class);Order order = coverBaseOrderVoToOrder(baseOrderVo);//订单商品if(StringUtils.isNotBlank(resultInfo[1])){List<OrderSub> orderSubs =JSON.parseObject(result.get(1), new TypeReference<List<OrderSub>>(){});order.setCustomerOrderSubs(orderSubs);}//订单预售if(StringUtils.isNotBlank(resultInfo[2])){PresaleOrderData presaleOrderData = JSON.parseObject(resultInfo[2],PresaleOrderData.class);order.setPresaleOrderData(presaleOrderData);}//订单发票if(StringUtils.isNotBlank(resultInfo[3])){OrderInvoice orderInvoice = JSON.parseObject(resultInfo[3],OrderInvoice.class);order.setOrderInvoice(orderInvoice);}//订单轨迹if(StringUtils.isNotBlank(resultInfo[5])){OrderTrackInfo orderTrackInfo = JSON.parseObject(resultInfo[5],OrderTrackInfo.class);order.setOrderTrackInfo(orderTrackInfo);}//订单履约信息if(StringUtils.isNotBlank(resultInfo[6])){List<OrderPremiseInfo> orderPremiseInfos =JSON.parseObject(result.get(6), new TypeReference<List<OrderPremiseInfo>>(){});order.setPremiseInfos(orderPremiseInfos);}//订单费用明细信息if(StringUtils.isNotBlank(resultInfo[7])){OrderFeeVo orderFeeVo = JSON.parseObject(resultInfo[7],OrderFeeVo.class);order.setOrderFeeVo(orderFeeVo);}return order;}
/**** @description 同时将多个 key-value (域-值)对设置到缓存中。* @param mappings 需要插入的数据信息*/public void mSetString(Map<String, String> mappings) {CallerInfo callerInfo = Ump.methodReg(UmpKeyConstants.REDIS.REDIS_STATUS_READ_MSET);try {redisClient.getClientInstance().mSetString(mappings);} catch (Exception e) {Ump.funcError(callerInfo);}finally {Ump.methodRegEnd(callerInfo);}}/**** @description 同时将多个key的结果返回。* @param queryKeys 查询的缓存key集合*/public List<String> mGet(List<String> queryKeys) {CallerInfo callerInfo = Ump.methodReg(UmpKeyConstants.REDIS.REDIS_STATUS_READ_MGET);try {return redisClient.getClientInstance().mGet(queryKeys.toArray(new String[0]));} catch (Exception e) {Ump.funcError(callerInfo);}finally {Ump.methodRegEnd(callerInfo);}return new ArrayList<String>(queryKeys.size());}
/*** @description pipeline放松查询数据* @param redisKeyList* @return java.util.List<java.lang.String>*/public List<String> getValueByPipeline(List<String> redisKeyList) {if(CollectionUtils.isEmpty(redisKeyList)){return null;}List<String> resultInfo = new ArrayList<>(redisKeyList);CallerInfo callerInfo = Ump.methodReg(UmpKeyConstants.REDIS.REDIS_STATUS_READ_GET);try {PipelineClient pipelineClient = redisClient.getClientInstance().pipelineClient();//添加批量查询任务List<JimFuture> futures = new ArrayList<>();redisKeyList.forEach(redisKey -> {futures.add(pipelineClient.get(redisKey.getBytes()));});//处理查询结果pipelineClient.flush();//可以等待future的返回结果,来判断命令是否成功。for (JimFuture future : futures) {resultInfo.add(new String((byte[])future.get()));}} catch (Exception e) {log.error("getValueByPipeline error:",e);Ump.funcError(callerInfo);return new ArrayList<>(redisKeyList.size());}finally {Ump.methodRegEnd(callerInfo);}return resultInfo;}




public static byte[] compressToByteArray(String text) throws IOException {ByteArrayOutputStream outputStream = new ByteArrayOutputStream();Deflater deflater = new Deflater();DeflaterOutputStream deflaterOutputStream = new DeflaterOutputStream(outputStream, deflater);deflaterOutputStream.write(text.getBytes());deflaterOutputStream.close();return outputStream.toByteArray();}
public static String decompressFromByteArray(byte[] bytes) throws IOException {ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);Inflater inflater = new Inflater();InflaterInputStream inflaterInputStream = new InflaterInputStream(inputStream, inflater);ByteArrayOutputStream outputStream = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int length;while ((length = inflaterInputStream.read(buffer)) != -1) {outputStream.write(buffer, 0, length);}inflaterInputStream.close();outputStream.close();byte[] decompressedData = outputStream.toByteArray();return new String(decompressedData);}
public static byte[] compressGzip(String str) {ByteArrayOutputStream outputStream = new ByteArrayOutputStream();GZIPOutputStream gzipOutputStream = null;try {gzipOutputStream = new GZIPOutputStream(outputStream);} catch (IOException e) {throw new RuntimeException(e);}try {gzipOutputStream.write(str.getBytes("UTF-8"));} catch (IOException e) {throw new RuntimeException(e);}finally {try {gzipOutputStream.close();} catch (IOException e) {throw new RuntimeException(e);}}return outputStream.toByteArray();}
public static String decompressGzip(byte[] compressed) throws IOException {ByteArrayInputStream inputStream = new ByteArrayInputStream(compressed);GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream);ByteArrayOutputStream outputStream = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int length;while ((length = gzipInputStream.read(buffer)) > 0) {outputStream.write(buffer, 0, length);}gzipInputStream.close();outputStream.close();return outputStream.toString("UTF-8");}
public byte[] zlibCompress(String message) throws Exception {String chatacter = "UTF-8";byte[] input = message.getBytes(chatacter);BigDecimal bigDecimal = BigDecimal.valueOf(0.25f);BigDecimal length = BigDecimal.valueOf(input.length);byte[] output = new byte[input.length + 10 + new Double(Math.ceil(Double.parseDouble(bigDecimal.multiply(length).toString()))).intValue()];Deflater compresser = new Deflater();compresser.setInput(input);compresser.finish();int compressedDataLength = compresser.deflate(output);compresser.end();return Arrays.copyOf(output, compressedDataLength);}
public static String zlibInfCompress(byte[] data) {String s = null;Inflater decompresser = new Inflater();decompresser.reset();decompresser.setInput(data);ByteArrayOutputStream o = new ByteArrayOutputStream(data.length);try {byte[] buf = new byte[1024];while (!decompresser.finished()) {int i = decompresser.inflate(buf);o.write(buf, 0, i);}s = o.toString("UTF-8");} catch (Exception e) {e.printStackTrace();} finally {try {o.close();} catch (IOException e) {e.printStackTrace();}}decompresser.end();return s;}

本篇文章来源于微信公众号:京东技术
本文来自投稿,不代表TakinTalks稳定性技术交流平台立场,如若转载,请联系原作者。

微信扫一扫