5. 一线大厂高并发缓存架构实战与性能优化

2023-11-20


本文是按照自己的理解进行笔记总结,如有不正确的地方,还望大佬多多指点纠正,勿喷。

课程内容:

1、中小公司Redis缓存架构以及线上问题分析

2、大厂线上大规模商品缓存数据冷热分离实战

3、实战解决大规模缓存击穿导致线上数据库压力暴增

4、黑客攻击导致缓存穿透线上数据库宕机Bug

5、一行代码解决线上缓存穿透问题

6、一次大V直播带货导致线上商品系统崩溃原因分析

7、突发性热点缓存重建导致系统压力暴增问题分析

8、基于DCL机制解决热点缓存并发重建问题实战

9、Redis分布式锁解决缓存与数据库双写不一致问题实战

10、大促压力暴增导致分布式锁串行争用问题优化实战

11、一次微博明星热点事件导致系统崩溃原因分析

12、利用多级缓存架构解决Redis线上集群缓存雪崩问题

1. 冷热数据分离

我们建议放缓存的地方都加一个超时时间,只需要对热点数据进行缓存,一些其他的冷门的数据就不用放到缓存里面占用时间了。

如果对于每天都有访问的数据就一直放在缓存里面,对于那些数据每查询一次可以加一点缓存超时延期。也就是读延期。这样以来那些有人访问的数据会一直在缓存里面,而那些没人访问的数据达到缓存的设定时间,就会从缓存里面移除。这样以来就做到了数据的冷热分离

2. 缓存设计

2.1 缓存击穿(失效)

由于大批量缓存在同一时间失效可能导致大量请求同时穿透缓存直达数据库,可能会造成数据库瞬间压力过大甚至挂掉,对于这种情况我们在批量增加缓存时最好将这一批数据的缓存过期时间设置为一个时间段内的不同时间。

如果商品上架或者更新商品,有那这批量更新、批量导入的。对商品进行批量操作,那商品的失效时间是一样的,同时过期。结果都没有缓存了,结果又有大量的请求。就是缓存里面没有了,但是数据库里面还有。

示例伪代码:

这个问题怎么解决呢?

那么我们可以把设置的超时时间设置成随机时间,在原来超时时间的基础上加一个随机数。

2.2 缓存穿透

缓存穿透是指查询一个根本不存在的数据,缓存层和存储层都不会命中,通常出于容错的考虑,如果从存储层查不到数据则不写入缓存层。

第一种情况:就是比如商品上架之后,一不小心把他彻底删除了,这样删除之后导致数据库以及缓存里面都没有了这个数据。结果后端数据全部没有了,而前端还一直有高并发的数据一直过来,导致大量的请求过来查数据库没有,查缓存也没有,这样一来缓存以及数据库的压力都比较大,特别是数据库。这个就叫做缓存穿透,有一个“透”字,就是把整个后端全部穿透了。

还有一种情况,就是如果是大型互联网,每天都有黑客来攻击你,假如他知道了你这个玩也链接中的数字就是你商品的id,那这个时候别人就可以攻击了,就是造一堆商品不存在的id,然后就用压测的软件去大量请求这个不存在商品,DDoS攻击,这样就会把数据层全部打穿、穿透。

缓存穿透将导致不存在的数据每次请求都要到存储层去查询,失去了缓存保护后端存储的意义。

造成缓存穿透的基本原因有两个:
第一,自身业务代码或者数据出现问题。
第二,一些恶意攻击、爬虫等造成大量空命中。缓存穿透问题解决方案:

那么这样的缓存穿透怎么解决呢?

可以设置一个空缓存。或者我们给一个特殊的标志,为了加以区分其他的情况,可以设置一个“{}”这样的空缓存。
这样看来是解决了黑客的攻击问题,但是如果有些黑客比较聪明,他不是拿一个商品攻击你,他每次都换着id去请求,一个数据库中有成千上万个空数据,那这样就会导致生成成千上万个空“{}”的缓存,又达到了攻击,那怎么解决呢?
过期,设置过期时间。空缓存可以设置几分钟过期之类的。如果他一直使用同一个商品,我们也可以设置一个商品的读延期时间。延期缓存就延期一两分钟的样子可以。

2.3 缓存雪崩

缓存雪崩指的是缓存层支撑不住或宕掉后,流量会像奔逃的野牛一样,打向后端存储层。

由于缓存层承载着大量请求,有效地保护了存储层,但是如果缓存层由于某些原因不能提供服务(比如超大并发过来,缓存层支撑不住,或者由于缓存设计不好,类似大量请求访问bigkey,导致缓存能支撑的并发急剧下降),于是大量请求都会打到存储层,存储层的调用量会暴增,造成存储层也会级联宕机的情况。

预防和解决缓存雪崩问题,可以从以下三个方面进行着手。

  1. 保证缓存层服务高可用性,比如使用Redis Sentinel或Redis Cl
    uster。
  2. 依赖隔离组件为后端限流熔断并降级。比如使用Sentinel或Hystrix限流降级组件。
    比如服务降级,我们可以针对不同的数据采取不同的处理方式。当业务应用访问的是非核心数据(例如电商商品属性,用户信息等)时,暂时停止从缓存中查询这些数据,而是直接返回预定义的默认降级信息、空值或是错误提示信息;当业务应用访问的是核心数据(例如电商商品库存)时,仍然允许查询缓存,如果缓存缺失,也可以继续通过数据库读取。
  3. 提前演练。在项目上线前,演练缓存层宕掉后,应用以及后端的负载情况以及可能出现的问题,在此基础上做一些预案设定。

3. 大V直播带货导致线上商品系统崩溃原因分析

像一些特别大的直播带货主播可能会上一些非常冷门的商品,就是之前根本没有买的商品,也没有访问的商品。但是当这些大主播们在直播间让大家抢这些商品的时候,可能一下几百万人去请求这个商品,但是这个商品在缓存里面没有,因为他是冷门的商品嘛。

假设现在一下有几万个请求来调用这个方法,然后查缓存是没有的,这个时候就会走到数据库这边来。但是数据的抗压能力很弱的。不过这个是小概率事件,因为可能这个冷门的商品在上架之前先进行访问就会缓存起来,我们不考虑这种情况,我们就考虑这种小概率的事件,就是这个冷门的商品缓存失效了,然后又有很多人来访问,现在就会压力全给到数据库,数据库承受压力很小的,这样就会导致数据库可能会挂掉。这样就会防止这种情况的。

虽然是小概率事件,我们还是要规避的。这就是突发性热点缓存重建导致系统压力暴增问题

4. 突发性热点缓存重建导致系统压力暴增问题

这个问题怎么解决呢?

最简单的方式就是加锁。就是单例模式里面有一个DCL(Double Check Lock)双重检测锁。这个就可以解决这个问题。

就是双重查询

在这里插入图片描述

对于那些突发性的热点缓存,并发重建的问题就解决了。一下来了几万条数据需要重建缓存,没关系,只有一个人能重建缓存。这个时候其他的请求就得等着这个重建缓存,但是等这个重建完成之后,进到这块代码的时候发现缓存里面有数据了,就不会再添加缓存了。

其实这样做还是回有问题,就是synchronized只在单节点内是有效的。如果这个是一个web应用的一个集群,用这个代码做的话,他的每个web服务器上都要重建一次,synchronized{this}中使用this肯定是不行的。就是比如101商品是在A的直播间里面加锁了,那么现在来了一个102商品在B直播间,是不是也阻塞住了,这样是不应该的,关键现在是不同的商品,现在因为一个商品会导致别的商品阻塞住。这个时候就可以使用分布式锁。把这个锁替换成分布式锁就得到了解决。分布式锁就是解决多节点间的并发问题。而且重建只需要建一次。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如果我们在开发的时候,开发着开发着发现里面的代码开始比较多了,且里面还有重复的,这个时候我们就可以重构一下:

在这里插入图片描述
在这里插入图片描述

这个时候仍然会有一个小问题

如果这个里面的数据是不存在的,然后里面放的是空缓存,但是我们这个时候返回的是null,再走到上面就会又去查数据库,这个时候是没必要的,因此需要区分一下。

在这里插入图片描述
在这里插入图片描述

5. 缓存数据库双写不一致问题

下面这两种情况全部都是缓存数据库双写不一致问题:

在这里插入图片描述

在这里插入图片描述

删除缓存同样也会有这样的问题

在这里插入图片描述

分布式锁就可以解决这个问题,

在这里插入图片描述

意思就是在一个线程操作的时候加上分布式锁即可

在这里插入图片描述

现在开始加锁

在这里插入图片描述

在更新、创建的地方都应该加这样的分布式锁,直接复制过去即可。

其实看着这样写了很多代码,会觉得在执行的时候效率很低。其实不是的,因为这个解决的是小概率事件,其中90%还是在缓存了就会读到。

其实在一些电商平台,基本上95%还是读操作,只有你加入购物车了或者是下单了才会涉及到写操作。也就是电商平台就是读多写少的问题,针对这个问题使用分布式锁去解决问题,可以借助分布式的读写锁优化,这种情况下可以借助分布式的读写锁redisson优化。读就加读锁,写就加写锁,因为写写会冲突,读写会冲突,但是读读是不会有冲突的。

如果现在大家伙都在读,在加读锁的时候是互相不冲突的,大家都可以进行读。也就是并行执行。秒杀之前大家都是读,都去并发执行,效率是很高的,也就那1s时间是有写读或者写写共存的情况。

在这里插入图片描述

  1. 第一句代码使用 Redisson 的 getReadWriteLock() 方法获取了一个名为 LOCK_PRODUCT_UPDATE_PREFIX + productId 的读写锁 productUpdateLock,用于保证对 productId 对应的数据的读写操作是互斥的。
  2. 第二句代码通过 productUpdateLock 的 writeLock() 方法获取了一个写入锁 writeLock,用于保证对 productId 对应的数据的写操作是互斥的。
  3. 第三句代码使用 writeLock 的 lock() 方法获取了写入锁,并阻塞当前线程,直到获取到锁为止。然后,该线程可以执行对 productId 对应数据的写操作。

这把读写锁,这个锁的key必须是一样的。

下面是读锁的底层源码:

在这里插入图片描述

如果第一个线程是写锁,现在来了一个线程,首先判断这个锁的模式,如果是读锁,那就把这个在写锁上加1,如果是写锁你就在这等着。

分布式锁有很多的优化场景,要根据不同的场景使用不同的锁。

下面这块应该使用不了读写锁优化,那么应该怎么来进行优化。

在这里插入图片描述

假如我们知道有99.99%的线程会在1s钟将这个方法里面的所有的步骤执行完,因此这个时候串行就可以转成并行

在这里插入图片描述
就是我等1s时间,如果我还加不上锁我就走了,返回方法。

package com.hs.distributlock.service;

import com.alibaba.fastjson.JSON;
import com.hs.distributlock.entity.ProductEntity;
import com.hs.distributlock.mapper.ProductMapper;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Objects;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @Description: 高并发缓存架构
 * @Author 胡尚
 * @Date: 2023/3/25 20:10
 */
@Service
public class ProductService {

    @Autowired
    StringRedisTemplate redisTemplate;


    @Autowired
    Redisson redisson;

    @Autowired
    ProductMapper productMapper;

    /**
     * 缓存穿透默认值
     */
    public static final String PRODUCT_PENETRATE_DEFAULT = "{}";

    /**
     * 突发性热点缓存重建时加的锁
     */
    public static final String LOCK_PRODUCT_HOT_CACHE_CREATE_PREFIX = "lock:product:hot_cache_create:";

    /**
     * 突发性热点缓存重建时加的锁
     */
    public static final String LOCK_CACHE_DB_UNLIKE_PREFIX = "lock:cache_db_unlike:";

    public void updateProduct(ProductEntity entity){
        
        // 解决缓存与数据库双写 数据不一致问题 而加写锁
        RReadWriteLock readWriteLock = redisson.getReadWriteLock(LOCK_CACHE_DB_UNLIKE_PREFIX + entity.getId());
        RLock wLock = readWriteLock.writeLock();
        wLock.lock();
        try {
            // 更新DB 更新缓存
            productMapper.update(entity);
            String json = JSON.toJSONString(entity);
            redisTemplate.opsForValue().set("product:id:" + entity.getId(), json, 12*60*60+getRandomTime(), TimeUnit.SECONDS);
        }finally {
            wLock.unlock();
        }
    }



    public void insertProduct(ProductEntity entity){
        // 解决缓存与数据库双写 数据不一致问题 而加写锁
        RReadWriteLock readWriteLock = redisson.getReadWriteLock(LOCK_CACHE_DB_UNLIKE_PREFIX + entity.getId());
        RLock wLock = readWriteLock.writeLock();
        wLock.lock();
        try {
            // 更新DB 更新缓存
            productMapper.insert(entity);
            String json = JSON.toJSONString(entity);
            redisTemplate.opsForValue().set("product:id:" + entity.getId(), json, 12*60*60+getRandomTime(), TimeUnit.SECONDS);
        }finally {
            wLock.unlock();
        }
    }



    /**
     * 重点方法,这其中使用了双重检测去查询缓存,还加了读锁去解决缓存和数据库双写导致的数据不一致问题
     */
    public ProductEntity queryProduct(Long id) throws InterruptedException {

        String productKey = "product:id:" + id;

        // 从缓存取数据
        ProductEntity entity = queryCache(productKey);
        if (entity != null){
            return entity;
        }

        // 突发性热点缓存重建问题,避免大量请求直接去请求DB,进而加锁拦截
        RLock lock = redisson.getLock(LOCK_PRODUCT_HOT_CACHE_CREATE_PREFIX + id);
        lock.tryLock(3, 30, TimeUnit.SECONDS);
        try {
            // 第二次验证 从缓存取数据
            entity = queryCache(productKey);
            if (entity != null){
                return entity;
            }

            // 缓存与DB数据双写不一致问题 加锁
            RReadWriteLock readWriteLock = redisson.getReadWriteLock(LOCK_CACHE_DB_UNLIKE_PREFIX + id);
            RLock rLock = readWriteLock.readLock();
            rLock.lock();
            try {
                // 查询数据库 更新缓存
                entity = queryDatabase(productKey, id);
            }finally {
                rLock.unlock();
            }
            
        }finally {
            lock.unlock();
        }
        return entity;
    }

    /**
     * 从缓存中查询
     */
    private ProductEntity queryCache(String key){
        ProductEntity entity = null;
        String json = redisTemplate.opsForValue().get(key);
        if (StringUtils.hasLength(json)){
            // 判断是否为解决缓存穿透而手动存储的值,如果是则直接返回一个新对象,并和前端约定好错误提示
            if (Objects.equals(PRODUCT_PENETRATE_DEFAULT, json)){
                return new ProductEntity();
            }
            entity = JSON.parseObject(json, ProductEntity.class);
            // 延期
            redisTemplate.expire(key, 12*60*60+getRandomTime(), TimeUnit.SECONDS);
        }

        return entity;
    }

    /**
     * 从数据库中查询,如果查询到了就将数据在缓存中保存一份,如果没有查询到则往缓存中存一个默认值来解决缓存击穿问题
     */
    private ProductEntity queryDatabase(String productKey, long id){
        ProductEntity entity = productMapper.get(id);
        // 如果数据库中也没有查询到,那么就往缓存中存一个默认值,去解决缓存击穿问题
        if (entity == null){
            redisTemplate.opsForValue().set(productKey, PRODUCT_PENETRATE_DEFAULT, 60*1000, TimeUnit.SECONDS);
        } else {
            redisTemplate.opsForValue().set(productKey, JSON.toJSONString(entity), 12*60*60+getRandomTime(), TimeUnit.SECONDS);
        }
        return entity;
    }

    private Integer getRandomTime(){
        return new Random().nextInt(5) * 60 * 60;
    }
}

在这段代码中,使用了Redisson提供的分布式锁来解决缓存和数据库双写导致的数据不一致问题。具体来说,使用了Redisson提供的读写锁(RReadWriteLock)来对缓存和数据库进行加锁。

在updateProduct和insertProduct方法中,首先获取了一个写锁(RReadWriteLock.writeLock())wLock,然后使用wLock.lock()方法获取锁并阻塞当前线程,直到获取到锁为止。在获取到锁之后,更新了数据库中的数据,然后更新了缓存中的数据,最后释放锁,以便其他线程能够获取锁并进行操作。

在queryProduct方法中,首先从缓存中查询数据,如果缓存中不存在,则使用Redisson提供的分布式锁(RLock)来解决突发性热点缓存重建问题。具体来说,使用redisson.getLock(LOCK_PRODUCT_HOT_CACHE_CREATE_PREFIX + id)获取一个名为LOCK_PRODUCT_HOT_CACHE_CREATE_PREFIX + id的锁lock,然后使用lock.tryLock(3, 30, TimeUnit.SECONDS)方法获取锁并阻塞当前线程,直到获取到锁为止。在获取到锁之后,再次从缓存中查询数据,如果缓存中不存在,则使用Redisson提供的读写锁(RReadWriteLock)来对缓存和数据库进行加锁。

具体来说,使用redisson.getReadWriteLock(LOCK_CACHE_DB_UNLIKE_PREFIX + id)获取一个名为LOCK_CACHE_DB_UNLIKE_PREFIX + id的读写锁readWriteLock,然后使用readWriteLock.readLock()获取一个读锁rLock,使用rLock.lock()方法获取锁并阻塞当前线程,直到获取到锁为止。在获取到读锁之后,查询数据库并更新缓存中的数据,最后释放读锁,以便其他线程能够获取锁并进行操作。最后,释放热点缓存重建锁,以便其他线程能够获取锁并进行操作。

需要注意的是,获取锁后必须执行对应的解锁操作,以便其他线程能够获取锁并进行操作。在上述代码示例中,使用了try-finally语句块来确保锁的释放。这样,即使在执行操作时抛出异常,也能够保证锁会被正确释放。

6. 一次微博明星热点事件导致系统崩溃原因分析

可能同时上百万的人访问,一个单个节点redis就是再缓存大概能支持10万个,因此redis可能也扛不住,redis扛不住,web请求可能就会报错。

也就是缓存雪崩

针对这种问题我们可以限流。这个即使前端代码层已经有限流,也要在后端也进行限流。万一前端没有限流成功,后端可以。也就是多加一级缓存,也就是多级缓存架构。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

5. 一线大厂高并发缓存架构实战与性能优化 的相关文章

  • 如何在多线程应用程序中使用 StackExchange.Redis IDatabase 对象?

    我从 StackExchange Redis 文档中收到有关如何使用 IDatabase 的混合消息 在里面基本使用文档 https github com StackExchange StackExchange Redis blob mas
  • 如何在redis中创建自己的数据库?

    There are 0 to 15 databases in redis 我想使用 redis cli 创建自己的数据库 有什么命令可以实现吗 Redis 数据库并不等同于 MySQL 等 DBMS 中的数据库名称 这是一种为键创建隔离和命
  • 保护节点 Redis

    我正在尝试保护 Node Redis IPC 服务器以使用私钥 公钥 我已经关注了本教程 http bencane com 2014 02 18 sending redis traffic through an ssl tunnel wit
  • 我的 Redis 自动生成的密钥

    我不知道我的 Redis 版本 4 0 9 到底发生了什么 我正在运行一个应用程序并使用 Redis 来存储我的数据库 但是 然后 Redis 自动创建 3 个新键 Backup1 Backup2 Backup3 并删除我的所有数据 这是我
  • redis集群不断打印日志WSA_IO_PENDING

    当我启动redis集群的所有redis服务器时 所有这些服务器不断打印类似WSA IO PENDING clusterWriteDone的日志 9956 03 Feb 18 17 25 044 WSA IO PENDING writing
  • Redis键空间事件不触发

    我有两个 Redis 客户端 在一个文件中我有一个简单的脚本设置并删除了 Redis 键 var redis require redis var client redis createClient 6379 127 0 0 1 client
  • 库存管理系统的 SQL 与 NoSQL

    我正在开发一个基于 JAVA 的网络应用程序 主要目的是拥有在多个称为渠道的网站上销售的产品的库存 我们将担任所有这些渠道的管理者 我们需要的是 用于管理每个渠道的库存更新的队列 库存表 其中包含每个通道上分配的正确快照 将会话 ID 和其
  • Docker-compose Predis 不通过 PHP 连接

    我正在尝试使用 docker compose 将 PHP 与 redis 连接 docker compose yml version 2 services redis image redis 3 2 2 php image company
  • Redis INCRBY 有限制

    我想知道是否有一种方法可以通过我的应用程序的单次往返在 Redis 中执行此操作 对于给定的键K 其可能值V是范围内的任意整数 A B 基本上 它有上限和下限 When an INCRBY or DECRBY发出命令 例如INCRBY ke
  • 如何批量删除Redis中数十万个带有特殊字符的key

    我们有一个包含数十万个 Redis 键的列表 其中包含各种特殊字符 我们希望批量删除它们 对于这个问题上的类似问题 有一些很好的答案 如何使用 Redis 自动删除与模式匹配的键 https stackoverflow com questi
  • 如何将 ActionController::Live 与 Resque + Redis 一起使用(用于聊天应用程序)

    我正在尝试为我的 Rails 应用程序构建聊天功能 我在用ActionController Live Puma Resque Redis为了这 所以基本上在这种情况下 redissubscribe方法正在后台运行 使用resque 到目前为
  • 在 aws-elasticache 上使用 memcached 或 Redis

    我正在 AWS 上开发一个应用程序 并使用 AWS elasticache 进行缓存 我对使用 memcached 或 redis 感到困惑 我阅读了有关 redis 3 0 2 更新以及它现在如何等同于 memchached 的文章 ht
  • 使用Redis从有限范围内生成唯一ID

    我有一些数据库项目 除了主键之外 还需要项目所属组的唯一索引 我们来调用属性nbr 以及将项目分组在一起并定义唯一范围的属性nbr 我们会打电话group This nbr必须在 1 N 范围内 并且may从外部源导入项目时进行设置 由于所
  • 如何在Redis中进行持久化存储?

    关闭redis服务器后 使用set存储的值被破坏 在这里我找到了使用持久性存储的方法 有人帮助我 如何使用javascript实现这一点 我想将客户端的一些值存储在 redis 数据库中 并且必须在其他客户端中使用该值 您需要配置 Redi
  • Redis Cluster 与 Pub/Sub 中的 ZeroMQ,用于水平扩展的分布式系统

    如果我要设计一个巨大的分布式系统 其吞吐量应随系统中的订阅者数量和通道数量线性扩展 哪个会更好 1 Redis集群 仅适用于Redis 3 0 alpha 如果是集群模式 您可以在一个节点上发布并在另一个完全不同的节点上订阅 消息将传播并到
  • redis - 使用哈希

    我正在使用 redis 为我的 Web 应用程序实现社交流和通知系统 我是 redis 的新手 我对哈希值及其效率有一些疑问 我读过这篇很棒的文章Instagram 帖子 http instagram engineering tumblr
  • Redis是如何实现高吞吐量和高性能的?

    我知道这是一个非常普遍的问题 但是 我想了解允许 Redis 或 MemCached Cassandra 等缓存 以惊人的性能极限工作的主要架构决策是什么 如何维持连接 连接是 TCP 还是 HTTP 我知道它完全是用C写的 内存是如何管理
  • 使用 Celery 通过 Gevent 进行实时、同步的外部 API 查询

    我正在开发一个 Web 应用程序 该应用程序将接收用户的请求 并且必须调用许多外部 API 来编写对该请求的答案 这可以直接从主 Web 线程使用 gevent 之类的东西来扇出请求来完成 或者 我在想 我可以将传入的请求放入队列中 并使用
  • 如何使 Redis 缓存中数据层次结构(树)的部分内容无效

    我有一些产品数据 需要在 Redis 缓存中存储多个版本 数据由 JSON 序列化对象组成 获取普通 基本 数据的过程很昂贵 将其定制为不同版本的过程也很昂贵 因此我想缓存所有版本以尽可能进行优化 数据结构看起来像这样 BaseProduc
  • redis 2.8.7 Linux Sentinel环境配置问题,如何使其自启动,应该订阅什么?

    现在我们尝试使用 redis 2 8 7 作为缓存存储 来自使用 booksleeve 客户端的 NET Web 应用程序 目前看来这是一个非常有趣和令人兴奋的任务 redis 文档非常好 但由于缺乏真正的实践经验 我确实有几个关于如何正确

随机推荐

  • 提升mysql服务器性能(系统参数与文件系统优化方案)

    加快TCP链接的回收 不应该使用CFQ cfq 完全公平队列 是anicipaory模式的替代品 没有过多的做预测性调度 而是根据给定的进程io优先级 直接来分配操作的顺序 最好使用 防止饥饿 xfs据说比较好 v
  • C# --- Struct and Record

    C Struct and Record Struct Record Struct struct是一种数据类型 和class非常类似 主要有以下的不同 struct是value type class是reference type 因为是val
  • log4j2配置文件

  • 机器学习-线性回归-多元梯度下降法

    目录标题 线性回归 多元线性回归 正规方程 线性回归 我们的回归方程常写成如下形式 h x 0 1 X 代价函数 J 12 i 1m h x i y i 2 看看代价函数到底是在干什么 如图 梯度下降是一个用来求函数最小值的算法 我们将使用
  • Echarts-折线图-设置线条颜色以及线条以下区域显示渐变颜色

    首先 先看折线图效果 1 设置线条颜色 在series中 数组项设置lineStyle属性 lineStyle 设置线条的style等 normal color red 折线线条颜色 红色 2 设置线条上点的颜色 也是图例的颜色 在seri
  • [OpenAirInterface实战-1] :什么是OAI?OAI常见问题解答

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 https blog csdn net HiWangWenBing article details 120490410 目录 前言 什么是软
  • 上拉加载原理

    实现思路 之前写过一篇触底加载 经过一番苦学钻研 优化一下 样式方面 滚动区域是给固定高度 设置 overflow y auto 来实现 接下来看看js方面的实现 其实也很简单 触发的条件是 可视高度 滚动距离 gt 实际高度 例子我会使用
  • 网络工程师学习笔记-------关于T1和E1载波

    关于T和E载波 标准模拟话音信号频率为4KHz 为了对模拟语音进行数字化 必须按至少8KHz的速率采样 采用7Bit进行量化即128级量化 则每个信道的比特率为 8KHz 7Bit 56Kb s 为了每一个这样的低速信道安装一条通信线路是不
  • 机器学习F1值的概念

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 一 什么是F1 score 二 计算过程 1 首先定义以下几个概念 2 通过第一步的统计值计算每个类别下的precision和recall 3 通过第二步计算结果计
  • openstack-nova-compute.service起不来

    1 启动服务 2 查看compute nova日志tail var log nova nova compute log 发现身份验证机制AMQPLAIN拒绝登录 3 关闭防火墙 root controller systemctl stop
  • 资讯汇总230217

    230217 22 48 美联储理事鲍曼 美国通胀仍旧太高 美联储理事鲍曼表示 美国通胀仍旧太高 美国当前的经济数据不一致 不同寻常的低失业率是一个好迹象 让通胀回到目标还有很长的路要走 需要继续加息 直到看到更多进展 财联社 230217
  • 西门子PLC如何与多个三菱PLC建立无线通信?

    对一个大型工厂 由于生产线的不断改造 新老流程的不断更新 这些PLC系统往往是由不同的制造商提供的 那么在智慧工厂的实现中 常会遇到不同品牌PLC之间需要进行相互通讯的情况 由于场地和生产能效的原因 在后期的系统改造中 通常需要采用无线的方
  • 构建流式应用—RxJS详解

    最近在 Alloyteam Conf 2016 分享了 使用RxJS构建流式前端应用 会后在线上线下跟大家交流时发现对于 RxJS 的态度呈现出两大类 有用过的都表达了 RxJS 带来的优雅编码体验 未用过的则反馈太难入门 所以 这里将结合
  • Oracle块损坏处理(MOS)

    处理 Oracle 块损坏 文档 ID 1526911 1 适用于 Oracle Database Enterprise Edition 版本 7 0 16 0 到 11 2 0 2 0 发行版 7 0 到 11 2 本文档所含信息适用于所
  • 微信小程序 如何返回上一个页面并实现刷新

    转载地址 https blog csdn net u011088792 article details 87938213 删除或编辑 之后返回 上一级并刷新 var pages getCurrentPages var beforePage
  • R语言实现RMF模型

    RMF模型说明 RMF模型是客户管理中 常被用来衡量客户价值和客户创利能力的重要方法 它主要考量三个指标 最近一次消费 Recency 近期购买的客户倾向于再度购买 消费频率 Frequency 经常购买的客户再次购买概率高 消费金额 Mo
  • 8年测试经验分享 —— 从0铸造测试技术壁垒

    前言 相信所有从事着软件测试或相关工作的同学都会思考一个问题 如何在持续且部分重复的测试活动中有效的进行测试技术积累 这个有趣的问题我先不予回答 我们先谈谈如何有效保证软件质量 作为团队中的质量保证者 需要深刻的意识到 验证系统原有功能是否
  • oracle 12c recover table恢复单表

    在 Oracle 12c 之前 如果误删一张表 常规的方法是 Flashback 闪回或 TSPITR 如果需要恢复的表空间过大 TSPITR 会耗时非常久 而开启 flashback 会消耗磁盘空间 在 12C 中oracle提供一个新功
  • java接口的详解

    文章目录 接口 1 1 接口的概念 1 2 接口语法规则 1 3 接口使用 1 4 接口特性 1 5 实现多个接口 1 6 接口间的继承 1 7 特殊的接口 1 7 1 Comparable接口实现compareTo方法 1 7 2 Com
  • 5. 一线大厂高并发缓存架构实战与性能优化

    分布式缓存技术Redis 1 冷热数据分离 2 缓存设计 2 1 缓存击穿 失效 2 2 缓存穿透 2 3 缓存雪崩 3 大V直播带货导致线上商品系统崩溃原因分析 4 突发性热点缓存重建导致系统压力暴增问题 5 缓存数据库双写不一致问题 6