当前位置: 首页 > news >正文

一线大厂高并发Redis缓存架构

文章目录

  • 高并发缓存架构设计
    • 架构设计思路
    • 完整代码
    • 开发规范与优化建议
      • 键值设计
      • 命令使用
      • 客户端的使用
    • 扩展
      • 布隆过滤器
      • redis的过期键的清除策略

高并发缓存架构设计

架构设计思路

首先是一个基础的缓存架构,对于新增、修改操作set会对缓存更新,对于查询操作先去查询redis缓存,没有再去查询DB,然后把数据在Redis中也缓存一份



但如果数据量很大,redis中不能存储所有的数据,而且很大一部分数据都是冷门数据,可能就插入时用了一次。对于这种情况我们就可以在新增或修改时对缓存set时加过期时间,在查询时将查询到的数据在缓存中更新过期时间,保证热点数据不过期,这样就简单的实现了冷热分离



考虑解决缓存击穿的情况,大量的数据同时间过期导致大量请求直接落到了DB上。在业务上肯定会有一些批量操作,那么对于批量新增的场景,多个数据设置了同一时间过期,那么就可能会出现缓存击穿的情况,解决方法是再加个随机方法,在原有过期时间上再增加一段随机时间



考虑解决缓存穿透的情况,管理员误删热点数据或恶意攻击,一直访问缓存和数据库中都不存在的数据,进而拖垮数据库。

我们可以选择往缓存中存一个空值+过期时间;或者是布隆过滤器。

这里最好是要区分一下,写一个方法区查询缓存,如果查询缓存没有查询到数据返回null,如果查询到了数据但是这个数据是我们上一步存的空值那么这里返回什么,最好是和前一步返回的null区分开



考虑解决热点数据缓存重建问题,热点数据过期或者是冷门数据忽然变成热点数据,这时缓存中没数据,DB中有数据,一瞬间大量的请求要查询这条数据就都落到了DB上。

解决方案是加锁,对查询DB操作加锁,这里需要加分布式锁,锁的粒度要小,比如电商中使用锁前缀+商品id。之所以要使用分布式锁而不是synchronized也是因为锁的粒度,使用synchronized(this)方式那么查询其他商品的操作也会被阻塞住,使用synchronized(锁前缀 + product.getId()) 这种方式生成的锁对象又不是同一个对象。为了性能,同时还需要参考单例模式的双重检测机制,将DCL(Double-Checked-Locking)机制也加上。

伪代码如下:

// 查询缓存
Object o = queryCache(keyStr);
if(o != null){return o;
}// 热点数据缓存重建  缓存没有查询到就加锁
lock.lock();
try{// 再查一遍Object o = queryCache(keyStr);if(o != null){return o;}// 还没有查询到就查询DB并往Redis中写queryDatabase(...);}finally {lock.unlock();
}



考虑解决缓存与DB双写不一致问题

双写不一致问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8u46PsEk-1679751253793)(picture/Redis/103029)]

读写不一致问题,假如更新操作时我不更新缓存,而是删除缓存嘞?如下所示也是有问题的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zKHwgJ77-1679751253794)(picture/Redis/103137)]

要解决上面这些问题的方法还是加锁,在查DB更新缓存、更新DB更新缓存这两个地方加同一把分布式锁。此时就会有人提问了:

  • 这么写一个简单的增删改查逻辑代码会变得很复杂
    如果并发不高或者能容忍这些问题的话,那么你可以不加这些校验代码,如果你想要解决这些小概率问题那么就必须要加相应的代码。

  • 这么写都是串行执行,效率不会很低吗?
    在上一步中我们对查询方法就加了DCL机制,绝大部分请求在两次校验时就从缓存中拿到数据返回了,根本不会进入到加锁的位置

Object o = queryCache(keyStr);
if(o != null){return o;
}// 解决热点数据缓存重建问题  缓存没有查询到就加锁
lock.lock();
try{Object o = queryCache(keyStr);if(o != null){return o;}// 这个方法中才是查询DB更新缓存,这里面才会加锁,但是大部分请求在上面两次查缓存中就已经拿到数据并返回了queryDatabase(...);}finally {lock.unlock();
}



接下来尝试对上面两种分布式锁做优化

首先是为了解决热点数据缓存重建问题而加的分布式锁,其实现在这种方式也能用了,因为只会有一个请求去查询DB然后写入缓存,其他阻塞的线程就会通过第二次验证从缓存中拿到数据返回。但是可能会有几万个请求都阻塞在了加锁的那一行中,我们可以使用trylock()方法来优化,指定一个最大等待时间,这样所有等待的线程一到时间就直接去执行第二个从缓存中取数据的代码了。

接下来是为了解决缓存与DB数据不一致问题而加的分布式锁,大部分的情况下我们业务都是读多写少,我们可以在这里使用读写锁来提高性能,更新DB更新缓存的地方使用写锁,缓存无数据 查询DB更新缓存的地方用读锁。



接下来考虑解决缓存雪崩的问题,我们都是请求–>web服务–>redis,如果并发量很大,多个web服务的请求到发到了一个redis节点上,redis处理不过来一秒十几万或更多的请求,那么redis就可能宕机或者是用户线程一直等待redis响应

如果redis宕机,那么业务代码try{}catch后一般就去查数据库了,大量的请求就会让数据库挂掉,接着再整个服务都不能访问了。

如果redis没宕机,用户线程一直等待redis数据返回,此时并发很高,web服务中线程得不到释放,又不断有新的请求进来,又导致微服务可能宕机,进而影响到整个系统宕机。

解决方法:

  • 限流,但万一中间件部分限流没有拦住,我们在代码层面也要做相应的处理,使用下面这种解决方案

  • 多级缓存,我们可以在JVM层面也加一层缓存,在访问Redis前先访问JVM层面的缓存。因为JVM是本机内存,并发访问可以达到每秒百万

    我们还需要一个单独的系统去维护JVM层面的缓存。确定什么样的数据能放缓存中;某个微服务节点更新了数据,其他节点的JVM层面的缓存也要更新等等情况。



完整代码

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 {@AutowiredStringRedisTemplate redisTemplate;@AutowiredRedisson redisson;@AutowiredProductMapper 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;}
}



开发规范与优化建议

键值设计

Key的设计

  • 可读性和可管理性。以业务名为前缀,用冒号分割。避免直接使用id作为key导致数据覆盖的情况。

  • 简洁性。保证语义的前提下,控制key的长度,不要太长

  • 不要包含空格、换行、单双引号以及其他特殊字符

value的设计

  • 避免bigkey

    字符串类型,最大512MB,但是一般超过10KB就认为是bigkey

    非字符串类型,hash、list、set、zset,一般它们的元素超过5000就任务是bigkey

    bigkey的危害:导致redis阻塞、网络拥堵

    一般产生bigkey的原因:按天统计某些功能或用户集合、将数据库查询到的数据序列化后存入缓存,我们要判断是否是所有字段都需要缓存

    优化bigkey:将一个bigkey拆分为多个数据、如果不可拆分则不要每次取所有的数据,比如hmget key field [field ...] 只读取其中某些元素

  • 选择合适的数据类型

    反例:

    set user:1:name tom 
    set user:1:age 19 
    set user:1:favor football
    

    正例:

    hmset user:1 name tom age 19 favor football
    
  • 控制key的生命周期,添加过期时间



命令使用

  • O(N)命令关注N的数量

    例如hgeall、lrange、smembers、zrange等并非不能用,但需要关注N的数量。

    有遍历的需求可以使用hscan、sscan、zscan代替。

  • 禁用命令:keys * 、flushall 、flushdb等

  • 使用批量操作提高效率,比如pipeline管道等

  • redis的事务不要过多使用,可以使用lua脚本来代替



客户端的使用

  • 避免所有业务使用同一个redis实例

    可以搭建多个redis集群,不同的微服务调用不同的redis集群,不相干的业务拆分,公共数据做服务化。

  • 使用带有连接池,有效控制连接提高效率

    JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
    jedisPoolConfig.setMaxTotal(5);
    jedisPoolConfig.setMaxIdle(2);
    jedisPoolConfig.setTestOnBorrow(true);JedisPool jedisPool = new JedisPool(jedisPoolConfig, "127.0.0.1", 6379, 3000, null);Jedis jedis = null;
    try {jedis = jedisPool.getResource();//具体的命令jedis.executeCommand()
    } catch (Exception e) {logger.error("op key {} error: " + e.getMessage(), key, e);
    } finally {//注意这里不是关闭连接,在JedisPool模式下,Jedis会被归还给资源池。if (jedis != null) jedis.close();
    }
    

    连接池参数含义:

    序号参数名含义默认值使用建议
    1maxTotal资源池中最大连接数8设置建议见下面
    2maxIdle资源池允许最大空闲的连接数8设置建议见下面
    3minIdle资源池确保最少空闲的连接数0设置建议见下面
    4blockWhenExhausted当资源池用尽后,调用者是否要等待。只有当为true时,下面的maxWaitMillis才会生效true建议使用默认值
    5maxWaitMillis当资源池连接用尽后,调用者的最大等待时间(单位为毫秒)-1:表示永不超时不建议使用默认值
    6testOnBorrow向资源池借用连接时是否做连接有效性检测(ping),无效连接会被移除false业务量很大时候建议设置为false(多一次ping的开销)。
    7testOnReturn向资源池归还连接时是否做连接有效性检测(ping),无效连接会被移除false业务量很大时候建议设置为false(多一次ping的开销)。
    8jmxEnabled是否开启jmx监控,可用于监控true建议开启,但应用本身也要开启

    一般我们控制最大连接数和资源池允许的最大空闲连接数这两个配置就行了

    Redis连接池的连接对象是懒加载的,连接池对象刚创建时不会初始化创建连接对象,是真正使用时才会去创建,我们可以做连接池预热

    // 先将创建的连接对象保存起来,然后再统一调用close()方法放回连接池中
    List<Jedis> minIdleJedisList = new ArrayList<Jedis>(jedisPoolConfig.getMinIdle());for (int i = 0; i < jedisPoolConfig.getMinIdle(); i++) {Jedis jedis = null;try {jedis = pool.getResource();minIdleJedisList.add(jedis);jedis.ping();} catch (Exception e) {logger.error(e.getMessage(), e);} finally {//注意,这里不能马上close将连接还回连接池,否则最后连接池里只会建立1个连接//jedis.close();}
    }
    //统一将预热的连接还回连接池
    for (int i = 0; i < jedisPoolConfig.getMinIdle(); i++) {Jedis jedis = null;try {jedis = minIdleJedisList.get(i);//将连接归还回连接池jedis.close();} catch (Exception e) {logger.error(e.getMessage(), e);} finally {}
    }
    



扩展

布隆过滤器

当布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那就肯定不存在。

布隆过滤器不能删除数据,如果要删除得重新初始化数据。

底层原理如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TMs6tLvs-1679807400908)(picture/Redis/81509)]

使用Redisson实现一个简单的案例

package com.redisson;import org.redisson.Redisson;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;public class RedissonBloomFilter {public static void main(String[] args) {// 构建一个redisson对象Config config = new Config();config.useSingleServer().setAddress("redis://localhost:6379");RedissonClient redisson = Redisson.create(config);RBloomFilter<String> bloomFilter = redisson.getBloomFilter("nameList");//初始化布隆过滤器:预计元素为100000000L,误差率为3%,根据这两个参数会计算出底层的bit数组大小bloomFilter.tryInit(100000000L,0.03);//将zhuge插入到布隆过滤器中bloomFilter.add("hushang");//判断下面号码是否在布隆过滤器中System.out.println(bloomFilter.contains("aabbcc"));//falseSystem.out.println(bloomFilter.contains("eeeee"));//falseSystem.out.println(bloomFilter.contains("hushang"));//true}
}

实际开发中的伪代码如下

//初始化布隆过滤器
RBloomFilter<String> bloomFilter = redisson.getBloomFilter("nameList");
//初始化布隆过滤器:预计元素为100000000L,误差率为3%
bloomFilter.tryInit(100000000L,0.03);//把所有数据存入布隆过滤器
void init(){for (String key: keys) {bloomFilter.add(key);}
}String get(String key) {// 从布隆过滤器这一级缓存判断下key是否存在Boolean exist = bloomFilter.contains(key);if(!exist){return "";}// 从缓存中获取数据String cacheValue = cache.get(key);// 缓存为空if (StringUtils.isBlank(cacheValue)) {// 从存储中获取String storageValue = storage.get(key);cache.set(key, storageValue);// 如果存储数据为空,往缓存中存一个空对象 需要设置一个过期时间(300秒)if (storageValue == null) {cache.expire(key, 60 * 5);}return storageValue;} else {// 缓存非空return cacheValue;}
}



redis的过期键的清除策略

  • 被动删除

    当调用get命令时去查询key是否过期,如果过期再删除

  • 主动删除

    Redis会定期(默认每100ms)主动淘汰一批已过期的key

  • 主动清理策略

    我们在redis.conf配置文件中配置maxmemory指定redis的最大使用内存,如果当前使用内存超过了这里配置的值则触发主动清理策略

主动清理策略共有8种,一般默认是不处理

  • 对于设置了过期时间的key
    • volatile-ttl:根据过期时间的先后进行删除,越早过期的越先被删除。
    • volatile-random:在设置了过期时间的键值对中,进行随机删除。
    • volatile-lru:会使用 LRU 算法筛选设置了过期时间的键值对删除。
    • volatile-lfu:会使用 LFU 算法筛选设置了过期时间的键值对删除。
  • 对于所有的key
    • allkeys-random:从所有键值对中随机选择并删除数据。
    • allkeys-lru:使用 LRU 算法在所有数据中进行筛选删除。
    • allkeys-lfu:使用 LFU 算法在所有数据中进行筛选删除。
  • 不处理
    • noeviction:不会剔除任何数据,拒绝所有写入操作并返回客户端错误信息"(error) OOM command not allowed when used memory",此时Redis只响应读操作。

LRU 算法(Least Recently Used,最近最少使用)

淘汰很久没被访问过的数据,以最近一次访问时间作为参考。

LFU 算法(Least Frequently Used,最不经常使用)

淘汰最近一段时间被访问次数最少的数据,以次数作为参考。


一般对于存在热点数据的访问场景下,选择LFU算法,这样避免了短时间新增了一批冷数据进而删除热点数据,但是LRU的效率要高

根据自身业务类型,配置好maxmemory-policy(默认是noeviction),推荐使用volatile-lru。

如果不设置maxmemory最大使用内存的话,redis将服务器的所有内存用完后,那么就会开始频繁的和磁盘进行交互了,会很慢。

对于主从模式,主节点删除过期的key后,会把del key命令同步到从节点执行

相关文章:

一线大厂高并发Redis缓存架构

文章目录高并发缓存架构设计架构设计思路完整代码开发规范与优化建议键值设计命令使用客户端的使用扩展布隆过滤器redis的过期键的清除策略高并发缓存架构设计 架构设计思路 首先是一个基础的缓存架构&#xff0c;对于新增、修改操作set会对缓存更新&#xff0c;对于查询操作…...

剑指offer-二维数组中的查找

文章目录题目描述题解一 无脑暴力循环题解二 初始二分法&#x1f315;博客x主页&#xff1a;己不由心王道长&#x1f315;! &#x1f30e;文章说明&#xff1a;剑指offer-二维数组中的查找&#x1f30e; ✅系列专栏&#xff1a;剑指offer &#x1f334;本篇内容&#xff1a;对剑…...

怎么设计一个秒杀系统

1、系统部署 秒杀系统部署要单独区别开其他系统单独部署&#xff0c;这个系统的流量肯定很大&#xff0c;单独部署。数据库也要单独用一个部署的数据库或者集群&#xff0c;防止高并发导致整个网站不可用。 2、防止超卖 100个库存&#xff0c;1000个人买&#xff0c;要保证不…...

程序参数解析C/C++库 The Lean Mean C++ Option Parser

开发中我们经常使用程序参数&#xff0c;根据参数的不同来实现不同的功能。POSIX和GNU组织对此都制定了一些标准&#xff0c;为了我们程序更为通用标准&#xff0c;建议遵循这些行业内的规范&#xff0c;本文介绍的开源库The Lean Mean C Option Parser就可以很好满足我们的需求…...

Java中的深拷贝和浅拷贝

目录 &#x1f34e;引出拷贝 &#x1f34e;浅拷贝 &#x1f34e;深拷贝 &#x1f34e;总结 引出拷贝 现在有一个学生类和书包类&#xff0c;在学生类中有引用类型的书包变量&#xff1a; class SchoolBag {private String brand; //书包的品牌private int size; //书…...

大文件上传

上图就是大致的流程一、标题图片上传课程的标题图片Ajax发送请求到后端后端接收到图片使用IO流去保存图片&#xff0c;返回图片的信息对象JS回调函数接收对象通过$("元素id").val(值)&#xff0c;方式给页面form表达img标签src属性值&#xff0c;达到上传图片并回显二…...

Python每日一练(20230327)

目录 1. 最大矩形 &#x1f31f;&#x1f31f;&#x1f31f; 2. 反转链表 II &#x1f31f;&#x1f31f; 3. 单词接龙 II &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日…...

Centos7 升级内核到5.10mellanox 编译安装

升级5.10内核 #uname -r 重启后 进入新的内核 进入新的内核信息 直接查看是看不到gcc版本 5.10需要高版本gcc 才可以进行编译...

冯诺依曼,操作系统以及进程概念

文章目录一.冯诺依曼体系结构二.操作系统&#xff08;operator system&#xff09;三.系统调用和库函数四.进程1.进程控制块&#xff08;PCB&#xff09;2.查看进程3.系统相关的调用4.fork介绍&#xff08;并发引入&#xff09;五.总结一.冯诺依曼体系结构 计算机大体可以说是…...

7.网络爬虫—正则表达式详讲

7.网络爬虫—正则表达式详讲与实战Python 正则表达式re.match() 函数re.search方法re.match与re.search的区别re.compile 函数检索和替换检索&#xff1a;替换&#xff1a;findallre.finditerre.split正则表达式模式常见的字符类正则模式正则表达式模式量词正则表达式举例前言&…...

关于位运算的巧妙性:小乖,你真的明白吗?

一.位运算的概念什么是位运算&#xff1f;程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算就是直接对整数在内存中的二进制位进行操作。位运算就是直接操作二进制数&#xff0c;那么有哪些种类的位运算呢&#xff1f;常见的运算符有与(&)、或(|)、异或(^)、…...

【Android车载系列】第5章 AOSP开发环境配置

1 硬件支持 建议空闲内存16G以上&#xff0c;同时硬盘400G以上 内存不够可以使用 Linux 的交换分区2 VMware Workstation安装 https://download3.vmware.com/software/wkst/file/VMware-workstation-full-16.1.1-17801498.exe2.1 Ubuntu镜像 http://mirrors.aliyun.com/ubun…...

个人时间管理网站—Git项目管理

&#x1f31f;所属专栏&#xff1a;献给榕榕&#x1f414;作者简介&#xff1a;rchjr——五带信管菜只因一枚&#x1f62e;前言&#xff1a;该专栏系为女友准备的&#xff0c;里面会不定时发一些讨好她的技术作品&#xff0c;感兴趣的小伙伴可以关注一下~&#x1f449;文章简介…...

2023最新ChatGPT整理的40道Java高级面试题

2023 年最火的就是 ChatGPT 了,很多同事使用他完成一些代码上的智能提示,也有人使用它发了财《「用ChatGPT年入百万!」各博主发布生财之道,网友:答辩搬运工》、《“躺着就能赚大钱”?ChatGPT火了,有人早就动起坏脑筋》等。 最近我也使用 ChatGPT 写技术文章了,比如:《…...

单机分布式一体化是什么?真的是数据库的未来吗,OceanBase或将开启新的里程碑

一. 数据 我们先说说数据这个东西&#xff0c;这段时间的ChatGPT在全世界的爆火说明了一件事&#xff0c;数据是有用的&#xff0c;并且大量的数据如果有一个合适的LLM大规模语言模型训练之后&#xff0c;可以很高程度的完成很多意想不到的事情。 我们大多数的时候的注意力只…...

100天精通Python丨基础知识篇 —— 03、Python基础知识扫盲(第一个Python程序,13个小知识点)

文章目录&#x1f41c; 1、Python 初体验Pycharm 第一个程序交互式编程第一个程序&#x1f41e; 2、Python 引号&#x1f414; 3、Python 注释&#x1f985; 4、Python 保留字符&#x1f42f; 5、Python 行和缩进&#x1f428; 6、Python 空行&#x1f439; 7、Python 输出&…...

springboot逍遥大药房管理系统

084-springboot逍遥大药房管理系统演示录像开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&a…...

ZYNQ中的GPIO与AXI GPIO

GPIO GPIO—一种外设&#xff0c;对器件进行观测和控制MIO—将来自PS外设和静态存储器接口的访问多路复用到PS引脚上处理器控制外设的方法—通过一组寄存器包括状态寄存器和控制寄存器&#xff0c;这些寄存器都是有地址的&#xff0c;通过这些寄存器的读写进行外设的控制sessi…...

接口导入功能

1.接口api export function import(param) { return fetch({ url: XXX.import, method: POST, headers: { Content-Type: multipart/form-data; }, data: param }) } 2.页面vue 和 js逻辑 <el-button :loading"disable&qu…...

网络安全知识点总结 期末总结

1、信息安全从总体上可以分成5个层次&#xff0c;密码技术 是信息安全中研究的关键点。 2、握手协议 用于客户机与服务器建立起安全连接之前交换一系列信息的安全信道。 3、仅设立防火墙系统&#xff0c;而没有 安全策略 &#xff0c;防火墙就形同虚设。 4、应用代理防火墙 …...

linux挂载远程目录

服务端操作 # 1、安装NFS程序 yum -y install nfs* rpcbind,在centos6以前自带的yum源中为portmap。 使用yum安装nfs时会下载依赖&#xff0c;因此只要下载nfs即可&#xff0c;无需再下载rpcbind. # 2、查看是否安装了nfs与rpcbind rpm -qa | grep nfs rpm -qa | grep rpc…...

ChatGPT—初识

ChatGPT初识 由于ChatGPT 注册相关的文章被平台限制了&#xff0c;所以有注册相关的问题可以私聊&#xff0c;或者可以代注册 Chat GPT是一款基于GPT模型的对话型AI模型&#xff0c;能够模拟真实的对话风格和行为方式&#xff0c;让人与AI的交互变得更加自然顺畅。下面将从Chat…...

【ArcGIS Pro二次开发】(18):地理处理工具类【Geoprocessing】补遗

ArcGIS Pro SDK 3.0中的Geoprocessing类是用于执行地理处理工具的核心类。地理处理工具是用于执行空间分析、数据转换、数据管理等任务的工具集&#xff0c;包括常见的空间分析工具、栅格处理工具、矢量处理工具、地图制图工具等。 之前有简单记录了下Geoprocessing工具的用法…...

国产芯片方案——红外测温体温计方案

红外测温体温计采用了热电堆式&#xff0c;利用塞贝克效应&#xff0c;将收集到的红外线光信号转化为电信号&#xff0c;再经过放大等处理&#xff0c;按内部的算法校正后再显示屏幕上输出具体温度值&#xff0c;能快速准确地测量人体体温。红外测温体温计广泛应用于医疗卫生、…...

详解ChatGPT的免费总结插件Glarity

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,科大讯飞比赛第三名,CCF比赛第四名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…...

RK3588平台开发系列讲解(NPU篇)NPU调试方法

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、日志等级二、NPU 支持查询设置项沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇我们一起来看一下NPU的调试方法。 一、日志等级 NPU 的运行库会根据开发板上的系统环境变量输出一些日志信息或者生成…...

基于微信小程序+爬虫制作一个表情包小程序

跟朋友聊天斗图失败气急败坏的我选择直接制作一个爬虫表情包小程序&#xff0c;从源头解决问题&#xff0c;从此再也不用担心在斗图中落入下风 精彩专栏持续更新↓↓↓ 微信小程序实战开发专栏 一、API1.1 项目创建1.2 图片爬虫帮助类1.3 测试窗体1.4 接口封装二、小程序2.1 项…...

TS常用数据类型(TypeScript常用数据类型,ts常用数据类型和js常用数据类型的区别)

简述&#xff1a;TS全称TypeScript&#xff0c;是一门弱类型的语言&#xff0c;可以理解为是 JavaScript 的扩展语法&#xff0c;因此我们可以在 ts 中继续写js代码&#xff0c;且不会报错&#xff0c;而且TypeScript 又叫做静态的JavaScript&#xff0c;可称为静态类型语言&am…...

关于Numpy的特殊符号@和矩阵运算

符号之谜 在Numpy中&#xff0c;看到了符号&#xff0c;但是无论是google搜索或者baidu搜索&#xff0c;由于符号是一个特殊字符&#xff0c;所以很难检索到答案。 其实很简单&#xff0c;他就是Numpy库中的一个操作符&#xff0c;在numpy库的说明中&#xff0c;落在numpy.mat…...

动态版通讯录——“C”

各位CSDN的uu们你们好呀&#xff0c;今天&#xff0c;小雅兰的内容是动态版通讯录啦&#xff0c;其实之前&#xff0c;我就已经写过静态版的通讯录了&#xff0c;只是存在着一些问题&#xff0c;具体细节可以详细看看我的静态版通讯录&#xff0c;好了&#xff0c;话不多说&…...

营销型网站规划建设的七大要素/推广平台免费b2b网站大全

几日来一直在看 马维达翻译的《ACE自适配通信环境中文技术文档》&#xff0c;终于看出点名堂决定从今日开始写代码调试工作工作系统的原型。虽说动作慢了点&#xff0c;不过连续阅读了《ACE文档》和Bruce Zhang的《软件设计精要与模式》多章&#xff0c;对设计模式有了更深刻的…...

开发一个网上商城/深圳seo公司

烟道口是开发商在建房子的时候&#xff0c;就已经预留好的&#xff0c;它的作用是用来排放厨房内的油烟。有的业主不知道自己家厨房烟道口的位置&#xff0c;那么厨房的烟道一般在什么位置&#xff1f;厨房烟道口位置可以改吗&#xff1f;也有的业主想要在烟道口贴瓷砖&#xf…...

微信公众号平台网站开发/北京seo排名公司

我是站在纯技术的角度上来考虑的&#xff0c;微软对MFC提供了源代码&#xff0c;而对C#只提供了一些组件。这对这个讨论起着至关重要的作用。 MFC是用C的语法来封装Windows的API&#xff0c;掌握MFC的关键不是在于记住掌握它的类库的使用方法&#xff0c;而是要学习它的源码。虽…...

wordpress 增加收录/百度论坛首页

一 常用命令 1、.gitignore 文件为git忽略文件&#xff0c;例*.[oa] *.~ 为忽略.a或.o或.~结尾的文件。/表示忽略目录&#xff0c;&#xff01;表示反取&#xff0c; *表示匹配零个或者多个字符。&#xff1f;表示匹配一个字符。 [0~9]表示0到9所有数字 2、如果部分更改文件已经…...

网站建设流程信息/网络推广100种方法

使用..表示上一层目录&#xff0c;使用.表示当前目录。文件夹或文件前面有.&#xff0c;则表示是掩藏文件 Home&#xff0c;分为root的Home和一般用户的home Bin目录里存放了常用的执行档&#xff0c;例如date、cal等。Bin和usr/bin的内容大致相同。预设情况下Usr/local/bin是空…...

重庆施工许可证查询系统/seo视频教程汇总

github https://github.com/marcosbarbero/spring-cloud-zuul-ratelimit spring-cloud-zuul-ratelimit 说明 spring-cloud-zuul-ratelimit是和zuul整合提供分布式限流策略的扩展 对请求的目标URL进行限流&#xff08;例如&#xff1a;某个URL每分钟只允许调用多少次&#xff09…...