微服务设计指导-让Redis循环写入时提高10倍的技巧

实战指南:基于ELK与Grafana构建天融信防火墙日志可视化看板 本文详细介绍了如何基于ELK与Grafana构建天融信防火墙日志可视化看板,包括环境准备、日志收集与解析配置、Elasticsearch存储优化、Grafana看板设计等关键步骤。通过实战案例和优化技巧,帮助用户高效处理天融信防火墙日志,实现安全态势的可视化监控与分析。 阅读详情

简介

有微服务的架构不代表性能好,而使用微服务的架构必须要求性能好。这句话不矛盾。矛盾在外面很多人认为微服务架构代表高并发,实际上不是。我们有“书面微服务”和“实际微服务”之说。比如说网上大量教人把httpConnection或者是FeignClient的timeout改成30秒就不会超时了?那这要什么微服务呢?微服务解决的到底是什么呢?

绝大多数人忘记了微信的本质是用来解决什么问题的。

互联网应用在To C端有6秒之说,即一个小程序/APP应用打开和加载过程>6秒,肯定新用户就不会再去用了,4秒算平均水平,一般大厂都是做到加载页面1秒。

各位要知道,任何一个“查询”式页面打开一秒,全站可能存在上千、上万个API,有时一个页面是需要通过几十个API组合在一起的。因此对于API在系统内我们互联网界的要求是约束在“一根API需要在前端万级并发的情况下+系统每张单表千万数据的Data Volumn下响应时间在100毫秒之内的“。

这就是1秒钟说的由来。

  • To C端界面加载1秒;
  • 任何微服务(即时响应类)要在100毫秒内

这是因为,你的应用上会有不少外联、不少回调、不少地图、配送、支付这种调用。它们都会对我们的应用造成“级联式雪崩”。

为了避免复杂系统的雪崩就需要及时“熔断、限流、升级”。这就是微服务的本质。

如果已经用了微服务架构、实际发觉这边老是超时,于是很多人一味地去放长这个连接时间自以为就解决了。

这样的人群占比大概超过90%(业界有统计)。

因此用了微服务即代表着对于开发的技能要求水平更高,任何可以提高100毫秒的地方都值得去做。

微服务架构里特别强调一个哲理“勿以善小而不为之,勿以恶小而为之”。

Redis在for循环里写大量数据的梗

通常情况我们经常会碰到要把千、万条数据一次写入Redis,在互联网应用场景中,我们经常把百万、千万级数据也会往Redis里塞,如:Redis Bloom。

经典的写法都是以下这样的:

@Test
    public void testForLoopAddSingleString() throws Exception {
        long startTime = System.currentTimeMillis();
        String redisValue = "";
        for (int i = 0; i < 10000; i++) {
            StringBuilder redisKey = new StringBuilder();
            redisKey.append("key_").append(i);
            redisValue = String.valueOf(i);
            redisTemplate.opsForValue().set(redisKey.toString(), redisValue);
        }
        long endTime = System.currentTimeMillis();
        long costTime = endTime - startTime;
        logger.info(">>>>>>test batch add into redis by using normal for loop spent->" + costTime);

    }

运行后得到如下输出:

Come on man,这才1万条数据,插入Redis要用4.7秒。

我用的是我一直用于模拟千万级数据量的服务器,这台服务器比公司的生产服务器性能还要好几倍,在这样的服务器性能上插入1万条数据都要4.7秒,生产上我们还要算上读存储出来再写Redis的网络开销,实际只会更慢。这种效率是不能忍受的。

增强版写法-Redis Piepeline写法

我们给Redis在它的“写操作上”,不需要增加任何第三方包,自带一颗“永久有效”写加速器,如下代码:

@Test
    public void testPipelineAddSingleString() throws Exception {
        RedisSerializer<String> keySerializer = (RedisSerializer<String>)redisTemplate.getKeySerializer();
        RedisSerializer<Object> valueSerializer = (RedisSerializer<Object>)redisTemplate.getValueSerializer();
        long startTime = System.currentTimeMillis();
        redisTemplate.executePipelined((RedisCallback<Object>)pipeLine -> {
            try {
                String redisValue = "";
                for (int i = 0; i < 10000; i++) {
                    StringBuilder redisKey = new StringBuilder();
                    redisKey.append("key_").append(i);
                    redisValue = String.valueOf(i);
                    pipeLine.setEx(keySerializer.serialize(redisKey.toString()), 10,
                        valueSerializer.serialize(redisValue));
                }
            } catch (Exception e) {
                logger.error(">>>>>>test batch add into redis by using pipeline for loop error: " + e.getMessage(), e);
            }
            return null;
        });
        long endTime = System.currentTimeMillis();
        long costTime = endTime - startTime;
        logger.info(">>>>>>test batch add into redis by using pipeline for loop spent->" + costTime);
    }

大家来看这种写法,你可以认为这种写法和for循环里套着一条条的update table set field=value变成了合并后一个batchUpdate的用法一样。看一下,这种写法带来的效率上的区别吧:

Oh My God。。。写法上有一点不同。

4,745毫秒 VS 564毫秒,我算它600毫秒好了,但这得差多少?各位想想。

下面同样给出相应的简单Hash结构的批量写Redis写法

假设我们要往redis里插一个这样的结构的Hash

@Test
    public void testPipelineAddHash() throws Exception {
        RedisSerializer<String> keySerializer = (RedisSerializer<String>)redisTemplate.getKeySerializer();
        RedisSerializer<Object> valueSerializer = (RedisSerializer<Object>)redisTemplate.getValueSerializer();
        long startTime = System.currentTimeMillis();
        String hashKey = "pipeline_hash_key";
        redisTemplate.executePipelined((RedisCallback<Object>)pipeLine -> {
            try {
                String redisValue = "";
                for (int i = 0; i < 10000; i++) {
                    StringBuilder redisKey = new StringBuilder();
                    redisKey.append("key_").append(i);
                    redisValue = String.valueOf(i);
                    pipeLine.hSet(keySerializer.serialize(hashKey), keySerializer.serialize(redisKey.toString()),
                        valueSerializer.serialize(redisValue));
                }
            } catch (Exception e) {
                logger.error(">>>>>>testPipelineAddHash by using pipeline for loop error: " + e.getMessage(), e);
            }
            return null;
        });
        long endTime = System.currentTimeMillis();
        long costTime = endTime - startTime;
        logger.info(">>>>>>testPipelineAddHash by using pipeline for loop spent->" + costTime);
    }

只用了500毫秒左右。

批量往Redis里插入复杂类型Hash的写法

如下,1万个JavaBean以Hash结构存在Redis里。

@Test
    public void testPipelineAddHashBean() throws Exception {
        RedisSerializer<String> keySerializer = (RedisSerializer<String>)redisTemplate.getKeySerializer();
        Jackson2JsonRedisSerializer jacksonSerial = new Jackson2JsonRedisSerializer<>(Object.class);
        long startTime = System.currentTimeMillis();
        String hashKey = "pipeline_hash_key";
        redisTemplate.executePipelined((RedisCallback<Object>)pipeLine -> {
            try {
                String redisValue = "";
                for (int i = 0; i < 10000; i++) {
                    StringBuilder redisKey = new StringBuilder();
                    redisKey.append("key_").append(i);
                    redisValue = String.valueOf(i);
                    UserBean user = new UserBean();
                    user.setUt(redisKey.toString());
                    user.setShareCode(redisValue);
                    pipeLine.hSet(keySerializer.serialize(hashKey), keySerializer.serialize(redisKey.toString()),
                        jacksonSerial.serialize(user));
                }
            } catch (Exception e) {
                logger.error(">>>>>>testPipelineAddHash by using pipeline for loop error: " + e.getMessage(), e);
            }
            return null;
        });
        long endTime = System.currentTimeMillis();
        long costTime = endTime - startTime;
        logger.info(">>>>>>testPipelineAddHash by using pipeline for loop spent->" + costTime);
    }

400毫秒左右(有时600毫秒、有时400毫秒、大多情况在400毫秒内)

Redis Bloom过滤器内的类Pipeline写法

同理,往Redis Bloom过滤器里喂值这个量还要大,那么喂入的越快,bloom拦截时的“黑窗期”就越短,对系统越有利。因此它也有同样的批量写入的好方法,如下代码:

public <T> void addByBloomFilter(BloomFilterHelper<T> bloomFilterHelper, String key, T value) {
        Preconditions.checkArgument(bloomFilterHelper != null, "bloomFilterHelper不能为空");
        int[] offset = bloomFilterHelper.murmurHashOffset(value);
        BitFieldSubCommands commands = BitFieldSubCommands.create();// 使用合并写法,假设10万条数据一个for需要12秒
        for (int i : offset) {
            commands = commands.set(BitFieldSubCommands.BitFieldType.unsigned(1)).valueAt(i).to(1);// 合并bit
        }
        redisTemplate.opsForValue().bitField(key, commands);// 再一次写入redis
    }

10万条数据用了45秒

如果用传统写法 如以下代码为传统写法

public <T> void addByBloomFilterSingleFor(BloomFilterHelper<T> bloomFilterHelper, String key, T value) {
        Preconditions.checkArgument(bloomFilterHelper != null, "bloomFilterHelper不能为空");
        int[] offset = bloomFilterHelper.murmurHashOffset(value);
        for (int i : offset) {
            redisTemplate.opsForValue().setBit(key, i, true);
        }
    }

10万条数据用了455秒

通过两个mark点确定某一个点的位置 read_image (Image0, '0.bmp') binary_threshold (Image0, Region, 'max_separability', 'dark', UsedThreshold) connection (Region, ConnectedRegions) fill_up (ConnectedRegions, RegionFillUp) select_shape_std (RegionFillUp, SelectedRegions, 'max_area', 70) red... 阅读详情

相关推荐

数字电路基础(CMOS电路、低功耗方法)

文章目录一、CMOS器件1.1.CMOS反相器1.2. CMOS与非门1.3.CMOS或非门1.4 CMOS与门和CMOS或门二、CMOS电路参数——功耗 一、CMOS器件 1.1.CMOS反相器 CMOS反相器实现非门功能,由一个PMOS管和一个NMOS管组成,其逻辑电路图如下: 其真值表如下: In PMOS NMOS Out 0 √ 导通 ×关闭 1 1 ×关闭 √...

Mr.翟的博客 1万+

RedisTemplate中BitFieldSubCommands的使用方法

spring-boot-starter-data-redis早就考虑到了这一点,所以为我们提供了一种。下面是最常规的做法,循环获取redis key中的偏移值,但是这种写法看着确实不太优雅....功能时,往往会遇到一个问题,我想要获取用户这个月打卡记录需要怎么做呢?需要创建一条一条的BitFieldSubCommand才有效。我们需要使用BitFieldSubCommands。需要注意,以下写法无效。

a1308003218的博客 1622

2024最新版Anaconda Navigator安装使用指南

本文简要介绍如何下载安装Anaconda Navigator最新版,以及如何使用Python内核搭载来完成应用程序开发。

jackson_lingua的博客 1万+

Redis 系列09--Redis BitMap

redis bitmap

fengxianaa的博客 811

TEM图像处理实战指南:从基础操作到金属材料分析

本文提供了一份全面的透射电镜(TEM)图像处理实战指南,涵盖从基础操作到金属材料深度分析的全流程。重点讲解了TEM图像预处理、选区电子衍射(SAED)标定、高分辨像(HRTEM)分析及STEM图像应用等核心技能,并结合金属材料(如铝合金、钢)的析出相鉴定、位错分析和界面结构研究等实际案例,帮助研究者从原始数据中准确提取晶体结构、缺陷及成分信息。

weixin_29284201的博客 211

ROS入门必学导航算法——Navigation

该平台集成了多款无人车底盘,包括履带式、四轮差速、阿克曼、麦克纳姆轮底盘等,以满足不同形式和配置的需求,并搭载了RTK定位系统、双目相机、深度相机和激光雷达等多种传感器,以满足开发者的科研需求。amcl节点接收里程计数据(通过"odom"话题)和激光雷达数据(通常通过"scan"话题),结合已知的地图,实时地估计出机器人在该地图上的位置。在ROS中,这是通过"tf库"变换实现的,通过将传感器数据转换到共同的参考系中,系统可以更容易地集成来自不同传感器的数据,并确保它们在相同的空间和时间范围内可用。

AMOVLAB(阿木实验室) 2910

黑马点评项目-用户签到

一、BitMap 的用法 假如我们用一张表来存储用户签到信息,其结构应该改如下: 假如有 1000 万个用户,平均每人每年签到次数为 10 次,则这张表一年的数据量为 1 亿条。每签到一次需要使用(8 + 8 + 1 + 1 + 3 + 1)共 22 字节的内存,一个月则最多需要 600 多字节。显然,这种方式不合适。 改进方案: 我们按月来统计用户签到信息,签到记录为 1,未签到则记录 0 将每一个 bit 位对应当月的每一天,形成了映射关系。用 0 和 1 表示业务状态,这种思路就成为位图(BItM

dingd1234的博客 936

使用kmplot在线进行生存分析

欢迎关注”生信修炼手册”!kmplot是一个生存分析的在线工具,最初是设计用来对肝癌中的miRNA进行生存分析,对应的文章发表在scientific reports上,链接如下https...

庐州月光的博客 1万+

redis签到

redis签到

bubbleJessica的博客 257

【A2DP】规范精讲[1]: 深入解析A2DP协议的核心架构

在蓝牙技术发展的早期阶段,音频传输主要通过SCO(同步面向连接)链路实现,这种设计主要针对语音通信,音质有限且功能单一。随着人们对无线高质量音频需求的增长,​​Advanced Audio Distribution Profile (A2DP)​​ 应运而生,成为蓝牙音频传输的技术基石。

byte轻骑兵的技术小窝 1万+

学Simulink——基于大数据处理与云计算的场景实例:无人机与云计算中心之间的高效数据传输链路设计

本文以无人机与云计算中心的高效数据传输链路设计为例,手把手指导使用Simulink进行系统级建模。针对智慧城市、灾害监测等场景中无人机采集的海量数据(视频、图像、点云等),构建包含数据源、传输协议、无线链路、云接入和性能分析的五层架构模型。通过智能数据压缩、多链路聚合和QoS优先级调度等关键技术,实现5G+Wi-Fi等多通信技术的自适应切换。仿真结果表明,5G+Wi-Fi链路聚合在城市环境中表现最优,而4G+卫星组合适合偏远地区。该模型为无人机实时数据传输提供了有效的设计方法和优化方向,可拓展至边缘计算、A

xiaoheshang_123的博客 120

让Redis循环写入时提高10倍的技巧

有微服务的架构不代表性能好,而使用微服务的架构必须要求性能好。这句话不矛盾。矛盾在外面很多人认为微服务架构代表高并发,实际上不是。我们有“书面微服务”和“实际微服务”之说。比如说网上大量教人把httpConnection或者是FeignClient的timeout改成30秒就不会超时了?那这要什么微服务呢?微服务解决的到底是什么呢?绝大多数人忘记了微信的本质是用来解决什么问题的。这是因为,你的应用上会有不少外联、不少回调、不少地图、配送、支付这种调用。它们都会对我们的应用造成“级联式雪崩”。...

Java_ttcd的博客 814

机器人控制算法九之 位姿描述与空间变换

机器人控制算法九之 位姿描述与空间变换

yohnyang的博客 1034

QPS提升10倍怎么设计-JAVA后端经常用到的技术

如果要将系统的 QPS(Queries Per Second,每秒查询率)提升 10 倍,可以从以下几个方面进行设计:一、硬件层面增加服务器资源可以增加服务器的数量,通过负载均衡将流量分发到不同的服务器上,从而提高系统的整体处理能力。例如,使用分布式服务器集群,将请求均匀地分配到各个节点上,避免单个服务器负载过高。升级服务器的硬件配置,如提高 CPU 性能、增加内存容量、使用更快的存储设备等。例如,采用多核处理器、大容量高速内存和固态硬盘,以加快数据的处理和读取速度。二、软件层面。

zhang9880000的博客 1618

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

微服务Redis循环写入性能提升

简介 有微服务的架构不代表性能好,而使用微服务的架构必须要求性能好。这句话不矛盾。矛盾在外面很多人认为微服务架构代表高并发,实际不是。我们有“书面微服务”和“实际微服务”之说。比如说网上大量教人把httpConnection或者是FeignClient的timeout改成30秒就不会超时了?那这要什么微服务呢?微服务解决的到底是什么呢? 绝大多数人忘记了微服务的本质是用来解决什么问题的。 互联网应用在To C端有6秒之说,即一个小程序/APP应用打开和加载过程>6秒,肯定新用户就不会再去用了,4

入门菜鸟程序员的成长 926

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

同事用了这个IDEA技巧,开发效率提升了10倍

开启Postfix Completion 在将今天的技巧前,我们需要作几个准备:IntellJ IDEA和开启Postfix Completion。 打开IDEA的Settings -> Editor -> General ->Postfix Completion,把这个框选上即可。 创建对象 .var 如果我们要创建一个Student对象,我们可以使用new Student().var。 Studentstudent=newStudent(); .ne...

wujialv的博客 311

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

微服务Spring Boot 整合Redis 基于Redis的Stream 消息队列 实现异步秒杀下单

Redis 实现秒杀下单,采用Stream消息队列实现,快!

wanghuichen的博客 8110

API和微服务设计的优化方式有哪些?

在构建响应迅速、用户体验良好的应用程序中,API性能的优化至关重要。在构建高性能的API时,采取综合策略是至关重要的。通过采用一系列策略,我们可以确保API在处理请求时高效运行,提供流畅的服务。

dream317 1449

Spring Boot性能优化:如何让应用速度提升10倍?

随着互联网应用的普及和用户需求的不断增长,性能优化成为现代软件开发中不可或缺的一部分。Spring Boot作为Java领域最受欢迎的微服务框架之一,提供了快速开发、自动配置和便捷部署的优势。然而,随着应用规模的扩大和用户流量的增加,性能问题逐渐成为瓶颈。本文将从多个方面探讨Spring Boot应用的性能优化策略,包括代码优化、数据库优化、缓存机制、异步处理、负载均衡、监控与调优等。通过实际案例和最佳实践,帮助开发者提升Spring Boot应用的性能,甚至实现速度提升10倍的目标。

小筱在线博客 1003
上一篇: 服务治理篇-应用架构的演变
下一篇: 顶配版 Spring 全家桶高级笔记+300道硬核面试题,跪着啃完了
JavaMonsterr
博客等级 码龄4年 211粉丝 481原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值