接口性能优化方案

聊聊接口性能优化的11个小技巧 前言 接口性能优化对于从事后端开发的同学来说,肯定再熟悉不过了,因为它是一个跟开发语言无关的公共问题。 该问题说简单也简单,说复杂也复杂。 有时候,只需加个索引就能解决问题。 有时候,需要做代码重构。 有时候,需要增加缓存。 有时候,需要引入一些中间件,比如mq。 有时候,需要需要分库分表。 有时候,需要拆分服务。 等等。。。 导致接口性能问题的原因千奇百怪,不同的项目不同的接口,原因可能也不一样。 本文我总结了一些行之有效的,优化接口性能的办法,给有需要的朋友一个参考。 1.索引 阅读详情

本文简单列举了几种从代码层面尽可能的解决接口性能的方案

大家如果还有什么更好的或者其他的方案,欢迎评论补充,相互学习

总共有以下几种:

  • 索引
  • sql的优化
  • 远程调用时的优化
  • 对重复查询数据库情况的处理
  • 异步处理
  • 避免大事务
  • 锁粒度
  • 分页
  • 缓存

索引

在使用索引时,首先应注意以下几个问题:

  • sql语句查询时,在关键字段、需要添加索引的字段是否添加了索引
  • 加的索引是否生效、要注意没生效的情况
  • 是否选错索引

常见的索引失效原因:

sql的优化

在写sql语句时,有很多方式和技巧,这里就不赘述了,简单用个思维导图列举一下。

远程调用时的优化

很多时候,我们需要在某个接口中调用其他服务的接口。

比如有这样的业务场景:

在用户信息查询接口中需要返回:用户名称、性别、等级、头像、积分、成长值等信息。

而用户名称、性别、等级、头像在用户服务中;积分在积分服务中;成长值在成长值服务中。

于是,查询用户信息需要调用用户服务,积分查询接口要调用积分服务,成长值查询接口要调用成长值服务。然后汇总数据统一返回

调用过程如下:

调用远程接口总耗时 530ms = 200ms + 150ms + 180ms

显然这种串行调用远程接口性能是非常不好的,调用远程接口总的耗时为所有的远程接口耗时之和。

那么如何优化远程接口性能呢?

有两种方式可以处理:

  • 并行调用
  • 使用redis保存冗余数据

并行调用

这里并行调用我们使用CompletableFuture

CompletableFuture相对来说比较灵活

调用远程接口总耗时 200ms = 200ms(即耗时最长的那次远程接口调用)

在java8之前可以通过实现Callable接口,获取线程返回结果。

java8以后通过CompletableFuture类实现该功能。我们这里以CompletableFuture为例:

 

public UserInfo getUserInfo(Long id) throws InterruptedException, ExecutionException {
    final UserInfo userInfo = new UserInfo();
    
    CompletableFuture userFuture = CompletableFuture.supplyAsync(() -> {
        getRemoteUserAndFill(id, userInfo);
        return Boolean.TRUE;
    }, executor);
 
    CompletableFuture bonusFuture = CompletableFuture.supplyAsync(() -> {
        getRemoteBonusAndFill(id, userInfo);
        return Boolean.TRUE;
    }, executor);
 
    CompletableFuture growthFuture = CompletableFuture.supplyAsync(() -> {
        getRemoteGrowthAndFill(id, userInfo);
        return Boolean.TRUE;
    }, executor);
    
    CompletableFuture.allOf(userFuture, bonusFuture, growthFuture).join();
 
    userFuture.get();
    bonusFuture.get();
    growthFuture.get();
 
    return userInfo;
}

//这两种方式别忘了使用线程池。示例中我用到了executor,表示自定义的线程池,为了防止高并发场景下,出现线程过多的问题。

redis保存冗余数据

上面说到的用户信息查询接口需要调用用户查询接口、积分查询接口和成长值查询接口,然后汇总数据统一返回。

那么,我们能不能把数据冗余一下,把用户信息、积分和成长值的数据统一存储到一个地方,比如:redis,存的数据结构就是用户信息查询接口所需要的内容。然后通过用户id,直接从redis中查询数据出来,不就可以了?

如果在高并发的场景下,为了提升接口性能,远程接口调用大概率会被去掉,而改成保存冗余数据的数据异构方案

但需要注意的是,如果使用了数据异构方案,就可能会出现数据一致性问题。

用户信息、积分和成长值有更新的话,大部分情况下,会先更新到数据库,然后同步到redis。但这种跨库的操作,可能会导致两边数据不一致的情况产生

对重复查询数据库情况的处理

对数据库的多次请求调用,无疑是非常耗时的,那么对于这种情况可以使用以下这几种方式的处理

循环查询数据库改为批量查询一次

public List<User> queryUser(List<User> searchList) {
    if (CollectionUtils.isEmpty(searchList)) {
        return Collections.emptyList();
    }
 
    List<User> result = Lists.newArrayList();
    searchList.forEach(user -> result.add(userMapper.getUserById(user.getId())));
    return result;
}

这里如果有50个用户,则需要循环50次,去查询数据库,其实每查询一次数据库,就是一次远程调用。
如果查询50次数据库,就有50次远程调用,这是非常耗时的操作。

优化方案:
提供一个根据用户id集合批量查询用户的接口,只远程调用一次,就能查询出所有的数据
注意:id集合的大小要做限制,最好一次不要请求太多的数据。要根据实际情况而定,建议控制每次请求的记录条数在500以内
public List<User> queryUser(List<User> searchList) {
    if (CollectionUtils.isEmpty(searchList)) {
        return Collections.emptyList();
    }
    List<Long> ids = searchList.stream().map(User::getId).collect(Collectors.toList());
    return userMapper.getUserByIds(ids);
}

 死循环

while(true) {
    if(condition) {
        break;
    }
    System.out.println("do samething");
}

这里使用了while(true)的循环调用,这种写法在CAS自旋锁中使用比较多。
当满足condition等于true的时候,则自动退出该循环。
如果condition条件非常复杂,一旦出现判断不正确,或者少写了一些逻辑判断,就可能在某些场景下出现死循环的问题。
出现死循环,大概率是开发人员人为的bug导致的,不过这种情况很容易被测出来。

递归

public void printCategory(Category category) {
  if(category == null 
      || category.getParentId() == null) {
     return;
  } 
  System.out.println("父分类名称:"+ category.getName());
  Category parent = categoryMapper.getCategoryById(category.getParentId());
  printCategory(parent);
}

无限递归没有设置终止条件的话,会导致内存溢出
建议写递归方法时,设定一个递归的深度,比如:分类最大等级有4级,则深度可以设置为4。
然后在递归方法中做判断,如果深度大于4时,则自动返回,这样就能避免无限循环的情况。

异步处理

当我们做接口性能优化,需要重新梳理一下业务逻辑,看看是否有设计上不太合理的地方。

比如有个用户请求接口中,需要做业务操作,发站内通知,和记录操作日志。为了实现起来比较方便,通常我们会将这些逻辑放在接口中同步执行,势必会对接口性能造成一定的影响。

接口内部流程图如下:

仔细梳理一下业务逻辑,会发现只有业务操作才是核心逻辑,其他的功能都是非核心逻辑。

在这里有个原则就是:核心逻辑可以同步执行,同步写库。非核心逻辑,可以异步执行,异步写库。

上面这个例子中,发站内通知和用户操作日志功能,对实时性要求不高,即使晚点写库,用户无非是晚点收到站内通知,或者运营晚点看到用户操作日志,对业务影响不大,所以完全可以异步处理

异步的方式主要有两种:多线程和mq

多线程

这里使用线程池的方式操作多线程

发站内通知和用户操作日志功能,被提交到了两个单独的线程池中。

这样接口中重点关注的是业务操作,把其他的逻辑交给线程异步执行,这样改造之后,让接口性能瞬间提升了。

但使用线程池有个问题就是:如果服务器重启了,或者是需要被执行的功能出现异常了,无法重试,会丢数据。

那么这个问题该怎么办呢?

mq

对于发站内通知和用户操作日志功能,在接口中并没真正实现,它只发送了mq消息到mq服务器。然后由mq消费者消费消息时,才真正的执行这两个功能。

这样改造之后,接口性能同样提升了,因为发送mq消息速度是很快的,我们只需关注业务操作的代码即可

具体mq的实现可以参考各个mq的实现逻辑,这里就不展示代码示例了

避免大事务

很多小伙伴在使用spring框架开发项目时,为了方便,喜欢使用@Transactional注解提供事务功能。

没错,使用@Transactional注解这种声明式事务的方式提供事务功能,确实能少写很多代码,提升开发效率。

但也容易造成大事务,引发其他的问题。

下面用一张图看看大事务引发的问题:

如何优化大事务:

  1. 少用@Transactional注解
  2. 将查询(select)方法放到事务外
  3. 事务中避免远程调用
  4. 事务中避免一次性处理太多数据
  5. 有些功能可以非事务执行
  6. 有些功能可以异步处理

 

锁粒度
 

在某些业务场景中,为了防止多个线程并发修改某个共享数据,造成数据异常。

为了解决并发场景下,多个线程同时修改数据,造成数据不一致的情况。通常情况下,我们会加锁。

但如果锁加得不好,导致锁的粒度太粗,也会非常影响接口性能。

所以一定要根据业务场景谨慎并且合理的进行锁设计,后续可以使用压测工具进行测试

示例如下:

synchronized

在java中提供了synchronized关键字给我们的代码加锁。

通常有两种写法:在方法上加锁 和 在代码块上加锁。

先看看如何在方法上加锁:

1、在方法上加锁
public synchronized doSave(String fileUrl) {
    mkdir();
    uploadFile(fileUrl);
    sendMessage(fileUrl);
}
这里加锁的目的是为了防止并发的情况下,创建了相同的目录,第二次会创建失败,影响业务功能。
但这种直接在方法上加锁,锁的粒度有点粗。因为doSave方法中的上传文件和发消息方法,是不需要加锁的。只有创建目录方法,才需要加锁。
我们都知道文件上传操作是非常耗时的,如果将整个方法加锁,那么需要等到整个方法执行完之后才能释放锁。显然,这会导致该方法的性能很差,变得得不偿失

2、在代码块上加锁
public void doSave(String path,String fileUrl) {
    synchronized(this) {
      if(!exists(path)) {
          mkdir(path);
       }
    }
    uploadFile(fileUrl);
    sendMessage(fileUrl);
}
这样改造之后,锁的粒度一下子变小了,只有并发创建目录功能才加了锁。而创建目录是一个非常快的操作,即使加锁对接口的性能影响也不大。
最重要的是,其他的上传文件和发送消息功能,任然可以并发执行。
当然,这种做在单机版的服务中,是没有问题的。但现在部署的生产环境,为了保证服务的稳定性,一般情况下,同一个服务会被部署在多个节点中。如果哪天挂了一个节点,其他的节点服务任然可用。
多节点部署避免了因为某个节点挂了,导致服务不可用的情况。同时也能分摊整个系统的流量,避免系统压力过大。
同时它也带来了新的问题:synchronized只能保证一个节点加锁是有效的,但如果有多个节点如何加锁呢?
答:这就需要使用:分布式锁了。目前主流的分布式锁包括:redis分布式锁、zookeeper分布式锁 和 数据库分布式锁。
由于zookeeper分布式锁的性能不太好,真实业务场景用的不多,这里先不讲

3、redis分布式锁
在分布式系统中,由于redis分布式锁相对于更简单和高效,成为了分布式锁的首先,被我们用到了很多实际业务场景当中
public void doSave(String path,String fileUrl) {
  try {
    String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime);
    if ("OK".equals(result)) {
      if(!exists(path)) {
         mkdir(path);
         uploadFile(fileUrl);
         sendMessage(fileUrl);
      }
      return true;
    }
  } finally{
      unlock(lockKey,requestId);
  }  
  return false;
}
跟之前使用synchronized关键字加锁时一样,这里锁的范围也太大了,换句话说就是锁的粒度太粗,这样会导致整个方法的执行效率很低。
其实只有创建目录的时候,才需要加分布式锁,其余代码根本不用加锁。
优化:
public void doSave(String path,String fileUrl) {
   if(this.tryLock()) {
      mkdir(path);
   }
   uploadFile(fileUrl);
   sendMessage(fileUrl);
}
 
private boolean tryLock() {
    try {   
    String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime);
    if ("OK".equals(result)) {
      return true;
    }
  } finally{
      unlock(lockKey,requestId);
  }  
  return false;
}
上面代码将加锁的范围缩小了,只有创建目录时才加了锁。这样看似简单的优化之后,接口性能能提升很多。
redis分布式锁虽说好用,但它在使用时,有很多注意的细节,隐藏了很多坑,如果稍不注意很容易踩中。

3、数据库分布式锁
mysql数据库中主要有三种锁:
表锁:加锁快,不会出现死锁。但锁定粒度大,发生锁冲突的概率最高,并发度最低。
行锁:加锁慢,会出现死锁。但锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
间隙锁:开销和加锁时间界于表锁和行锁之间。它会出现死锁,锁定粒度界于表锁和行锁之间,并发度一般。

并发度越高,意味着接口性能越好。
所以数据库锁的优化方向是:优先使用行锁,其次使用间隙锁,再其次使用表锁

分页处理

查询的数据量太大,可以分页后再处理

有时候我会调用某个接口批量查询数据,比如:通过用户id批量查询出用户信息,然后给这些用户送积分。

但如果你一次性查询的用户数量太多了,比如一次查询2000个用户的数据。参数中传入了2000个用户的id,远程调用接口,会发现该用户查询接口经常超时。

调用代码如下:

List users = remoteCallUser(ids);

众所周知,调用接口从数据库获取数据,是需要经过网络传输的。如果数据量太大,无论是获取数据的速度,还是网络传输受限于带宽,都会导致耗时时间比较长。

这样的情况可以使用分页处理:将一次获取所有的数据的请求,改成分多次获取,每次只获取一部分用户的数据,最后进行合并和汇总。

处理这个问题,要分为两种场景:同步调用 和 异步调用。

同步调用,使用分页优化

如果需要获取2000个用户的信息,它要求只要能正确获取到数据就好,对获取数据的总耗时要求不太高。

但对每一次对数据库的调用耗时有要求,不能大于500ms,不然会有邮件预警。

这时,我们可以同步分页调用批量查询用户信息接口

List<List<Long>> allIds = Lists.partition(ids,200);
for(List<Long> batchIds:allIds) {
   List<User> users = remoteCallUser(batchIds);
}
代码中使用google的guava工具中的Lists.partition方法,用它来做分页简直太好用了,不然要巴拉巴拉写一大堆分页的代码。

异步调用

如果需要获取2000个用户的信息,它考虑的就需要更多一些。

除了需要考虑查询数据库的耗时之外,还需要考虑该接口的总耗时,也不能超时500ms。

这时候用上面的同步分页请求远程接口,肯定是行不通的。

那么,只能使用异步调用了

List<List<Long>> allIds = Lists.partition(ids,200);
final List<User> result = Lists.newArrayList();
allIds.stream().forEach((batchIds) -> {
   CompletableFuture.supplyAsync(() -> {
        result.addAll(remoteCallUser(batchIds));
        return Boolean.TRUE;
    }, executor);
})
使用CompletableFuture类,多个线程异步调用远程接口,最后汇总结果统一返回

缓存

解决接口性能问题,加缓存是一个非常高效的方法。

但不能为了缓存而缓存,还是要看具体的业务场景。毕竟加了缓存,会导致接口的复杂度增加,它会带来数据不一致问题。

在有些并发量比较低的场景中,比如用户下单,可以不用加缓存。

还有些场景,比如在商城首页显示商品分类的地方,假设这里的分类是调用接口获取到的数据,但页面暂时没有做静态化。

如果查询分类树的接口没有使用缓存,而直接从数据库查询数据,性能会非常差。

那么如何使用缓存呢?

redis

通常情况下,我们使用最多的缓存可能是:redis和memcached。

但对于java应用来说,绝大多数都是使用的redis,所以接下来我们以redis为例。

由于在关系型数据库,比如:mysql中,菜单是有上下级关系的。某个四级分类是某个三级分类的子分类,这个三级分类,又是某个二级分类的子分类,而这个二级分类,又是某个一级分类的子分类。

这种存储结构决定了,想一次性查出这个分类树,并非是一件非常容易的事情。这就需要使用程序递归查询了,如果分类多的话,这个递归是比较耗时的。

所以,如果每次都直接从数据库中查询分类树的数据,是一个非常耗时的操作。

这时我们可以使用缓存,大部分情况,接口都直接从缓存中获取数据。操作redis可以使用成熟的框架,比如:jedis和redisson等。

用jedis伪代码如下:

String json = jedis.get(key);
if(StringUtils.isNotEmpty(json)) {
   CategoryTree categoryTree = JsonUtil.toObject(json);
   return categoryTree;
}
return queryCategoryTreeFromDb();
先从redis中根据某个key查询是否有菜单数据,如果有则转换成对象,直接返回。如果redis中没有查到菜单数据,则再从数据库中查询菜单数据,有则返回。
此外,我们还需要有个job每隔一段时间,从数据库中查询菜单数据,更新到redis当中,这样以后每次都能直接从redis中获取菜单的数据,而无需访问数据库了。

二级缓存

 

上面的方案是基于redis缓存的,虽说redis访问速度很快。但毕竟是一个远程调用,而且菜单树的数据很多,在网络传输的过程中,是有些耗时的。

有没有办法不经过请求远程,就能直接获取到数据呢?

答:使用二级缓存,即基于内存的缓存。

除了自己手写的内存缓存之后,目前使用比较多的内存缓存框架有:guava、Ehcache、caffine等。

我们在这里以caffeine为例,它是spring官方推荐的

第一步,引入caffeine的相关jar包
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
    <version>2.6.0</version>
</dependency>

第二步,配置CacheManager,开启EnableCaching
@Configuration
@EnableCaching
public class CacheConfig {
    @Bean
    public CacheManager cacheManager(){
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        //Caffeine配置
        Caffeine<Object, Object> caffeine = Caffeine.newBuilder()
                //最后一次写入后经过固定时间过期
                .expireAfterWrite(10, TimeUnit.SECONDS)
                //缓存的最大条数
                .maximumSize(1000);
        cacheManager.setCaffeine(caffeine);
        return cacheManager;
    }
}

第三步,使用Cacheable注解获取数据
@Service
public class CategoryService {
   
   @Cacheable(value = "category", key = "#categoryKey")
   public CategoryModel getCategory(String categoryKey) {
      String json = jedis.get(categoryKey);
      if(StringUtils.isNotEmpty(json)) {
         CategoryTree categoryTree = JsonUtil.toObject(json);
         return categoryTree;
      }
      return queryCategoryTreeFromDb();
   }
}

调用categoryService.getCategory()方法时,先从caffine缓存中获取数据,如果能够获取到数据,则直接返回该数据,不进入方法体。

如果不能获取到数据,则再从redis中查一次数据。如果查询到了,则返回数据,并且放入caffine中。

如果还是没有查到数据,则直接从数据库中获取到数据,然后放到caffine缓存中。

具体流程图如下:

 

该方案的性能虽然更好,但有个缺点:如果数据更新了,不能及时刷新缓存,此外,如果有多台服务器节点,可能存在各个节点上数据不一样的情况。

由此可见,二级缓存给我们带来性能提升的同时,也带来了数据不一致的问题。

使用二级缓存一定要结合实际的业务场景,并非所有的业务场景都适用。

但上面我列举的分类场景,是适合使用二级缓存的。因为它属于用户不敏感数据,即使出现了稍微有点数据不一致也没有关系,用户有可能都没有察觉出来

如何在实际需求中权衡接口性能优化的技术方案与产品需求? 在软件开发中,接口性能优化是一项复杂的任务,涉及技术实现、业务需求、时间限制和资源分配等多方面因素。本文探讨了如何在技术方案与产品需求之间进行权衡,帮助团队做出理性决策。首先,明确核心业务需求和优先级,确保优化目标与产品目标一致。其次,选择适合的优化方案,权衡投入产出比,优先考虑短期内见效的技术,如数据库索引优化、缓存技术和API限流。此外,还需考虑长期的可扩展性和维护成本,避免引入复杂度过高的技术架构。最后,评估技术限制与开发资源,选择适合团队能力的优化方案,并通过持续迭代与反馈,确保系统在满足产品需求的 阅读详情

相关推荐

JAVA下单接口优化实战TPS性能提高10倍

今天小编就为大家分享一篇关于JAVA下单接口优化实战TPS性能提高10倍,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

接口优化的11种方法

接口性能优化对于从事后端开发的同学来说,肯定再熟悉不过了,因为它是一个跟开发语言无关的公共问题。 该问题说简单也简单,说复杂也复杂。 有时候,只需加个索引就能解决问题。 有时候,需要做代码重构。 有时候,需要增加缓存。 有时候,需要引入一些中间件,比如mq。 有时候,需要需要分库分表。 有时候,需要拆分服务。 等等。。。 导致接口性能问题的原因千奇百怪,不同的项目不同的接口,原因可能也不一样。 本文我总结了一些行之有效的,优化接口性能的办法,给有需要的朋友一个参考。 1.索引 接口性

只为成功找方法 不为失败找借口 9442

GIS坐标系转换以及空间校正和地理配准

许多小伙伴都对坐标系,投影这类问题迷迷糊糊,我之前也一样,现在总结一下。 坐标系的转换1.为什么要进行坐标系的转换?2. 不同坐标系的介绍1.地理坐标系我国常见的地理坐标(1).北京54坐标系(2).西安80坐标系(3).WGS-84坐标系(4).大地2000坐标系2.投影坐标系我国常用的投影坐标系(1) UTM投影(2) 高斯-克吕格投影(3) 兰伯特投影(4) 阿尔伯斯投影投影坐标系的选择3. 坐标系的转换1.已知坐标系之间的转换1.1 两坐标系的参考椭球相同1.2 两坐标系的参考椭球不一致,但是GIS

m0_47258611的博客 8912

api接口优化思路

接口优化

weixin_43498142的博客 229

【物联网】探索NE555:一款经典的集成电路(超详细)

NE555是一种集成电路,其内部结构包括比较器、RS触发器、电压比较器和输出级三个主要功能模块,外部引脚则提供了与其他电路元件进行连接的接口。NE555的设计目的是为了提供一种简单方便的定时器解决方案,它广泛应用于模拟和数字电路中。NE555作为一款经典的集成电路,具备设计简单、易于使用和稳定可靠的特点,在电子领域发展了广泛的应用。从单稳态模式到多稳态模式,再到振荡器模式,NE555可以满足不同的需求,并且可以与其他电路元件灵活组合,扩展其功能。然而,需要注意的是NE555也有一些限制。

Goforyouqp的博客 6万+

手把手教你用AirSim生成无人机训练数据集:RGB/深度图/分割图全攻略

本文详细介绍了如何使用AirSim仿真插件在UE4环境中生成无人机训练数据集,涵盖RGB、深度图和分割图等多种模态数据的采集与处理。通过实战指南,读者可以掌握环境配置、多模态数据采集、自动化流程设计及数据后处理等关键技术,为无人机视觉算法开发提供高质量训练数据。

weixin_29008805的博客 446

实战总结,18种接口优化方案的总结

18种 接口 优化方案的总结

robinson_911的专栏 404

完美解决 mysql 报错ERROR 1524 (HY000): Plugin ‘mysql_native_password‘ is not loaded

mysql 报错ERROR 1524 (HY000): Plugin 'mysql_native_password' is not loaded

xiaohua616的博客 4万+

接口性能优化的11个小技巧,大家务必掌握!

???? 这是一个或许对你有用的社群???? 一对一交流/面试小册/简历优化/求职解惑,欢迎加入「芋道快速开发平台」知识星球。下面是星球提供的部分资料:《项目实战(视频)》:从书中学,往事上“练”《互联网高频面试题》:面朝简历学习,春暖花开《架构 x 系统设计》:摧枯拉朽,掌控面试高频场景题《精进 Java 学习指南》:系统学习,互联网主流技术栈《必读 Java 源码专栏》:知其然,知其所以然????这是一个或许...

芋艿V 644

【新手必看】挖漏洞流程指南,黑客手把手教你挖漏洞月入过万!收藏这篇就够了!(附学习笔记)

【新手必看】挖漏洞流程指南,黑客手把手教你挖漏洞月入过万!收藏这篇就够了!(附学习笔记)【新手必看】挖漏洞流程指南,黑客手把手教你挖漏洞月入过万!收藏这篇就够了!(附学习笔记)

weixin_57514792的博客 1103

电路板保险丝如何选型

在电路板保险丝选型过程中,需要考虑多个因素以确保其适合特定的电路需求。最后,经过以上程序选定的样品需要在实际的电路中进行测试,以验证所选择的保险丝是否合适。

weixin_57010826的博客 1310

服务端接口性能优化方案总结

针对老项目,去年做了许多降本增效的事情,其中发现最多的就是接口耗时过长的问题,就集中搞了一次接口性能优化。本文将给小伙伴们分享一下接口优化的通用方案。

技术引领业务创新 1万+

使用MATLAB结合EasySpin进行ESR模拟的详细步骤及示例代码

安装EasySpin:确保你已经安装了EasySpin工具箱,它可以帮助你进行ESR模拟。你可以从EasySpin的官方网站(https://easyspin.org/)下载并安装。准备实验数据:将实验得到的EPR数据整理成合适的格式,一般包含磁场(Magnetic Field)和信号强度(Intensity)两列。进行模拟:使用EasySpin的函数对单线态氧自由基和超氧自由基进行模拟。调整参数:通过调整模拟参数,使模拟得到的峰型和峰位置与实验数据尽可能匹配。导出数据。

AI的内部世界的博客 2003

http接口性能优化方案

要实现跨机房调用的HTTP接口并保持响应时间在80ms以下,确实面临多个技术挑战。

maoer95209520的博客 1392

ESP32-IDF开发实例-外部Flash与FatFs文件系统数据存取

FatFs是用于小型嵌入式系统的通用FAT / exFAT文件系统模块。FatFs模块是按照ANSI C(C89)编写的,并且与磁盘I/O层完全分开。因此,它独立于平台。它可以并入资源有限的小型微控制器中,例如8051,PIC,AVR,ARM,Z80,RX等。ESP32-IDF对FatFs提供了良好的支持。

视觉与物联智能 2915

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

慢接口性能优化总结的18种方案

在海量数据场景下,‌NoSQL并非完全替代关系型数据库‌,而是通过互补架构解决特定性能瓶颈。对于深分页、模糊搜索等需求,Elasticsearch等NoSQL数据库通过‌倒排索引‌和‌分布式计算‌显著提升查询效率‌28,而分库分表更适用于保障核心事务的ACID特性‌6。实际选型需综合‌查询模式‌、‌数据规模‌和‌运维成本‌进行权衡‌45。

qq_38371336的博客 1921

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

服务端接口性能优化有哪些方案?

作为一个Java后台开发,我们写出的大部分代码都决定着用户的使用体验。如果我们的后端代码性能不好,那么用户在访问我们的网站时就要浪费一些时间等待服务器的响应。这可能导致用户投诉甚至用户的流失。关于性能优化是一个很大的话题。《Java程序性能优化》说性能优化包含五个层次:设计调优、代码调优、JVM调优、数据库调优、操作系统调优等。而每一个层次又包含很多方法论和最佳实践。本文不想大而广的概述这些内容。只是举几个常用的Java代码优化方案,读者看完之后可以真正的实践到自己代码中的方案。

qq_38196449的博客 1348

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

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

visio安装包

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

项目接口性能优化方案

身为一个合格的开发者,在系统开发时不仅仅是要考虑功能的实现,还要考虑接口性能以此来提升用户体验、节省硬件成本。本文总结了系统开发中常见的接口性能优化手段。有关于项目接口性能优化方案到此就结束了。

DaenCode的博客 2381

后端API接口性能优化的10种方案,真有用!

优化前: 优化后: 打个比喻:耗时操作,考虑用异步处理,这样可以降低接口耗时。假设一个转账接口,匹配联行号,是同步执行的,但是它的操作耗时有点长,优化前的流程: 为了降低接口耗时,更快返回,你可以把匹配联行号移到异步处理,优化后:除了转账这个例子,日常工作中还有很多这种例子。比如:用户注册成功后,短信邮件通知,也是可以异步处理的~至于异步的实现方式,你可以用线程池,也可以用消息队列实现。在适当的业务场景,恰当地使用缓存,是可以大大提高接口性能的。缓存其实就是一种空间换时间的思想,就是你把要查的数

IT枫斗者的博客 1971

性能优化 - 案例篇:11种优化接口性能的通用方案

本文总结了11条接口性能优化法则,涵盖数据库、接口逻辑、缓存及分布式架构等领域。重点包括:使用索引优化SQL查询,避免全表扫描;并行调用远程服务减少响应时间;数据异构减少服务依赖;异步处理非核心任务;控制锁粒度提高并发;分页优化避免大偏移;合理使用缓存减轻数据库压力;分库分表解决大数据量问题;精简接口逻辑提升效率。优化需权衡改动成本与收益,以最小代价实现性能提升。

小工匠 1932

真实需求中的接口性能优化-技术与产品方案的取舍

自适应降级:考虑极端情况下,算法推荐服务挂了,我们需要有一种机制让投放C端不下发这个需要算法推荐的banner(比如学习熔断机制,一个接口总是调用失败,那么直接快速失败——商品推荐一直失败,那么这个banner就不要下发了)一个很朴素的想法如上,我们负责的投放系统C端可以并行的调用券投放服务和商品推荐服务,并且在商品推荐服务完成后再调用商品打包服务获取价格和图片信息(因为获取价格和图片前提是得到商品推荐服务返回的商品id,因此这里需要串行)如上是算法的推荐流程,可以看到,算法推荐逻辑也是有先后顺序依赖的。

dasdjsdsa的博客 917
上一篇: 搭建SpringBoot项目
下一篇: 解决报错:java: java.lang.NoSuchFieldError: Class com.sun.tools.javac.tree.JCTree$JCImport
到长安送荔枝
博客等级 码龄3年 108粉丝 10原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值