redis缓存核心知点

  • 一、主流应用架构
  • 二、缓存知识考点
  • 三、多路I/O复用模型
  • 四、常用的数据类型
  • 五、消息队列
  • 六、Redis的持久化
    • 6.1 BGSAVE原理
    • 6.2 RBD持久化的缺点
    • 6.3 持久化方式之AOF
    • 6.4 AOF文件重写
    • 6.5 Redis数据的恢复
    • 6.7 RDB和AOF的优缺点
    • 6.8 RDB-AOF混合持久化方式(新版本的默认备份方式)
  • 七、Pipeline及主从同步
    • 7.1 Pipeline的简介
    • 7.2 redis的同步机制
    • 7.3 redis的主从同步原理
    • 7.4 全同步过程
    • 7.5 增量同步过程
    • 7.6 redis sentinel(redis哨兵)
    • 7.7 流言协议Gossip
  • 八、redis集群
    • 8.1 实现原理
    • 8.2 如何从海量数据里快速找到所需
    • 8.4 hash环的数据倾斜问题

一、主流应用架构

  • 1.穿透查询,缓存层里没有客户端需要的数据,需要穿透缓存层,访问存储层。
  • 2.回种,穿透查询得到数据后,会回写到缓存层,以便下次同样的数据请求可以直接快速从缓存层返回。
  • 3.熔断,如果存储层挂掉或者不提供服务,直接可以从缓存层返回数据。

二、缓存知识考点

2.1 缓存中间件——Memcache和Redis的区别?

Memacache:代码层次类似Hash,简单易用。

  • 1.支持简单数据类型
  • 2.不支持数据持久化存储
  • 3.不支持主从
  • 4.不支持分片,分割数据进行存储

2.2 Redis:主流缓存中间件

  • 1.数据类型丰富
  • 2.支持数据磁盘持久化存储
  • 3.支持主从
  • 4.支持分片

2.3 从海量Key里查询出某一固定前缀的Key

首先,摸清数据规模,问清楚边界。

1.使用Keys对线上业务的影响,Keys pattern:查找所以符合给定模式pattern的key。

  • 1.KEYS指令一次性返回所有匹配的key。
  • 2.健的数量过大会使服务卡顿,对于内存的消耗、redis的服务都会有影响。

2.使用SCAN cursor [MATCH pattern] [COUNT count]

  • 1.SCAN指令可以无阻塞的提取出指定pattern模式的key列表,每次执行都只会返回少量元素,可以用于生产环境,不会带来阻塞服务器的问题。其中cursor为游标。
  • 2.基于游标的迭代器,需要基于上一次的游标延续之前的迭代过程。
  • 3.以0作为游标开始一次新的迭代,直到命令返回游标0万次一次遍历。
  • 4.不保证每次执行都返回某个给定数量的元素,支持模糊查询。
  • 5.一次返回的数量不可控,只能是大概率符合count参数。
  • 6.每次返回的是匹配到的数据和匹配到哪的cursor,返回的游标cursor不是递增的,因此会匹配到重复的值,需要外部程序(hash Set)进行去重。分批次遍历,因此花费的时间较keys更长。

2.4 业务:记录每个用户访问网站的次数?

方案:只需拼接用户id和当前日期(精确到日即可)的字符串作为key,每次用户访问该页面,对key进行一次incr操作即可。

2.5 如何通过redis实现分布式锁?

分布式锁是控制分布式系统访问共享资源的一种锁的实现。

分布式锁需要解决的问题:

  • 1.互斥性,任一时刻只能有一个客户端获取锁。
  • 2.安全性,只能由持有该锁的客户端删除。
  • 3.死锁,获取锁的客户端因为各种原因无法释放锁,而导致其他客户端不能获取锁。
  • 4.容错,

方法一:使用setnx、expire实现,当一个客户端A setnx返回1,表示获取锁。另一个客户B setnx返回为0,便会进行阻塞,直到调用expire设置key的生存时间,key过期()时,表示A释放锁。B setxnx返回为1,表示获得锁。虽然两个操作都是原子性,但是组合在一起就是非原子性。缺点:原子性得到不满足。

RedisServer redisServer = SpringUtils.getBean(RedisServer.class);
long status = rediServer.setnx(key,"1");
if (status == 1){redisServer.expire(key,expire);//执行业务
}

方法二:SET key value [EX seconds] [px milliseconds] [NX|XX](EX second:设置键的过期时间为second秒、px milliseconds:设置键的过期时间为milliseconds毫秒、NX:只在键不存在时,才对键进行设置操作,效果与setnx类似、XX:只在键已经存在时,才对键进行设置操作,效果与setnx相反、SET操作成功完成时,返回OK,否则返回nil)。

RedisServer redisServer = SpringUtils.getBean(RedisServer.class);
String result = redisServer.set(lockKey,requestId,SET_IF_NOT_EXIST,SET_WITH_EXRIRE_TIME,expireTime);//set lockt 122 ex 10 nx
if ("ok".equals(result)){//执行业务
}

2.6 大量的key同时过期的注意事项

大量key同时过期可能会发生缓存雪崩问题。类似的缓存问题还有缓存穿透、缓存击穿等问题。

集中过期,由于清除大量的key很耗时,会出现短暂的卡顿现象。可以在设置key的过期时间时,给每个key加上随机值。

2.7 如何使用redis做异步队列?

使用List作为队列,RPUSH生产消息,LPOP消费信息。

  • 1.缺点:没有等待队列里有值就直接消费。
  • 2.弥补:可以通过在应用层引入Sleep机制去调用LPOP重试。
  • 3.更加精确的操作:BLPOP key [key] timeout ,引入blpop 阻塞直到队列有消息或超时。
  • 4.缺点:只能提供一个消费者进行消费。
  • 5.方法:使用pub/sub主题订阅者模式。
    • 发送者(pub)发送消息,订阅者(sub)接收消息。
    • 订阅者可以订阅任意数量的频道。
    • pub发送消息(publish mytopic “hello”)给频道topic(mytopic),该消息会发送给订阅该topic频道的sub(subscribe mytopic)。
  • 缺点:消息的发布是无状态的,无法保证可达。如果某个订阅者下线,是无法接收到的,此时需要特殊的消息队列kafka。

2.8 redis这么快的原因?(100000+QPS)

  • 1.完全基于内存,绝大部分请求是纯粹的内存操作,不受磁盘I/O限制,执行效率较高。
  • 2.数据结构简单,对数据操作也简单。redis不使用表、不用预定义。其存储结构就是键值对,所以对数据的操作时间复杂度都是O(1)。
  • 3.采用单线程(只针对处理I/O请求的主线程,在处理除了I/O有关的业务时,还是多线程),单线程也能处理高并发请求,想多核也可以启动多实例。
    • 一般的处理高并发(并发并非并行)请求,会把I/O线程和业务线程分开,业务线程都存储在一个线程池中,避免线程的频繁创建和销毁,但是redis对于高并发的请求不是如此。
    • redis对于高并发的请求,使用的是主线程为单线程的结构,主线程:处理I/O事件、I/O对应的相关业务的处理、过期存储键的处理、主从协调、集群协调。这些除了I/O有关的业务都会被封装为一个周期性的任务,进行周期性的处理。对于客户端的请求,都由一个主线程串行进行处理,避免了频繁的上下文切换和锁竞争。
  • 4.使用多路I/O复用模型,非阻塞IO。
    • redis的I/O操作是单线程的,所有的操作都是线性执行的,所以某一请求如果需要等待用户进行读写操作,就会阻塞I/O,从而影响其他的客户端的请求响应。所以引入了I/O多路复用。

以下都是对上述考点原理的深度解析,包括:数据持久化、主从同步、redis集群、数据分片等

三、多路I/O复用模型

FD:File Descriptor,文件描述符。一个打开的文件通过唯一的描述符进行引用,该描述符就是打开的元数据到文件本身的映射。


在多路I/O复用模型中,最重要的就是Select系统调用。Selector可以监听多个文件描述符的可读可写,并返回可读可写的描述符个数。

redis采用的I/O多路复用函数:epoll、kqueue、evport、select。

  • 1.因地制宜,选择合适的函数
  • 2.优先选择时间复杂度为O(1)的I/O多路复用函数(epoll、kqueue、evport)作为底层实现。
  • 3.以时间复杂度为O(n)的select作为保底。
  • 4.基于react设计模式监听I/O事件。
    • redis采用了react设计模式来实现文件事件处理器,文件事件处理器采用I/O多路复用模块,同时监听多个FD。

四、常用的数据类型

redis的操作属于原子性。

  • 1.String:最基本的数据类型,二进制安全。
  • 2.Hash:String元素组成的字典,适用于存储对象。和实体类对象很相似,可以过hmset创建、hget获取、hset赋值。我们经常将结构化的信息在客户端序列化,存储为一个字符串的值,一般以json的格式,此时使用redis的hash就很适合。
  • List:列表,按照String元素插入顺序排序。类似于栈,先进(lpush)后出。
  • Set:String元素组成的无序集合,通过hash表实现,不允许重复。使用sadd进行添加。利用Set的可以存储一些集合性的数据,Set提供了求并集、差集、交集等操作。因此可以用在求共同喜好、共同关注等场景中。
  • Sorted Set:通过分数(可重复)来为集合中的成员进行从小到大的排序。每个元素都会关联到一个double类型的数据。可以使用zset作带权重的队列,对任务进行分数的排列,实现重要的任务先执行。
  • 用于计数的HyperLogLog,用于支持存储地理位置信息的Geo。
  • 上述的数据类型底层数据类型基础:简单动态字符串、链表、字典、跳跃表、整数集合、压缩列表、对象。

五、消息队列

当不需要立即获得结果,但是并发量又需要进行控制的时候,差不多就是需要使用消息队列的时候。

消息队列主要解决了应用耦合、异步处理、流量削锋等问题。当前使用较多的消息队列有RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMq等,而部分数据库如Redis、Mysql以及phxsql也可实现消息队列的功能。

六、Redis的持久化

redis提供了三种持久化方式,将数据保存到磁盘中,避免数据丢失。

redis的所有配置都保存在redis.conf文件中,当服务器启动时,会自动加载redis.conf中的配置信息。save——可以根据redis的读写情况,合理配置备份。stop-writes-on-bgsave-error yes——当备份进程出错时,主进程停止redis的写入,保证持久化的数据一致性。redis属于cpu密集型服务器。数据的备份格式为.rdb二进制格式。

  • 1.RDB(快照)持久化,保存某个时间点的全量数据快照。

    • SAVE:阻塞Redis的服务器进程,直到RDB文件被创建完毕。很少被使用,因为save操作时在主进程中,而redi是用一个主进程处理所有的请求,这种方式会阻塞所有的请求。
    • BGSAVR:Fork出一个子进程来创建RDB文件,不阻塞服务器进程。主进程继续接收请求,子进程完成文件的创建之后,会发送信号给主进程,与此同时,主进程在接收请求的同时,会通过轮询来接收子进程的信号。可以通过lastsave(返回上次执行备份的时间)来查看子进程RDB是否完成。可以通过java的定时器调用bgsave指令进行redis的备份。(如何定期保存某个时间点的全量数据备份?可以通过定时器调用bgsave 备份为时间戳命名的文件)
  • 2.自动化触发RDB持久化

    • 根据redis.conf配置里的SAVE m n定时触发(用的BGSAVE)
    • 主从复制时,主节点自动触发
    • 执行Debug Reload
    • 执行Shutdown 且没有开启AOF持久化
  • 3.AOF进行持久化

6.1 BGSAVE原理

  • 1.执行BGSAVE指令。检查当前主进程是否有正在执行的AOF和RDB子进程,如果有就返回错误( 防止子进程之间的竞争,也意味着当redis进行bgsave时,客户端发送的bgsave指令会被服务器拒绝执行);如果没有,就会触发持久化。
  • 2.调用redis的rdbSaveBackground()方法执行fork系统调用(实质上redis的rdb操作是调用了操作系统的系统调用fork指令)。fork指令是创建进程的,实现了Copy-on-Write。
    • fork指令Copy-on-Write,当父进程创建子进程时,只为子进程创建虚拟空间,父子进程使用的是相同的物理空间,只有父子进程发生更改时,才会为子进程分配独立的物理空间。
    • Copy-on-Write,如果多个调用者同时要求相同资源,他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本给该调用者,而其他调用者所访问到的仍是最初的资源。
  • 3.此时父子进程共享相同的物理页面,当主进程处理写请求时。通过COW,系统会为要修改的页面创建副本,而不是写共享的页面,所以子进程的地址空间内的数据是fork时刻整个数据库的快照。
  • 4.当子进程完成临时文件的写入,用临时文件替换原来的快照文件。最后,子进程退出,完成一次备份操作。

6.2 RBD持久化的缺点

  • 1.内存数据的全量同步,数据量过大会由于I/O而严重影响性能。
  • 可能会因问redis挂掉而丢失从当前到最近一次快照期间的数据。(此时可以采用AOF)

6.3 持久化方式之AOF

AOF(Append-Only-File)持久化:保存写状态。也就是说AOF不是像RDB记录数据库状态,而是记录数据库接收到的指令。修改redis.conf里的配置使其生效。

  • 1.记录除了查询以外的所有变更数据库状态的指令。
  • 2.以append的形式追加保存到AOF文件中(增量)。

6.4 AOF文件重写

解决AOF文件不断增大的问题

  • 1.执行BGWRITEAOF指令。检查当前主进程是否有正在执行的AOF和RDB子进程,如果有就返回错误( 防止子进程之间的竞争,也意味着当redis进行BGWRITEAOF时,客户端发送的BGWRITEAOF指令会被服务器拒绝执行);如果没有,就会触发持久化
  • 2.使用rewriteAppendOnlyFileBackground()方法调用fork(),创建子进程。
  • 3.子进程把新的AOF(新的AOF重写是直接把当前内存中的数据生成对应的命令——这一步极大的可以简化AOF文件中的内容,不需要合并、分析旧的AOF文件)写到一个临时文件里,不依赖原AOF文件。
  • 4.主进程持续将新的变动同时写到内存buff和原来的AOF里(即使重写失败,保证数据的安全)。
  • 5.主进程获取子进程重写AOF的完成信号,将buff内容往新AOF同步增量变动。
  • 6.使用新的AOF文件替换掉旧的AOF文件。

6.5 Redis数据的恢复

RDB和AOF文件共存情况下的恢复流程。

6.7 RDB和AOF的优缺点

  • 1.RDB优点:全量数据快照,文件小,恢复快。
  • 2.RDB缺点:无法保存最近一次快照之后的数据。
  • 3.AOF优点:可读性高,适合保存增量数据,数据不易丢失。
  • 4.AOF缺点:文件体积大,恢复时间长。

6.8 RDB-AOF混合持久化方式(新版本的默认备份方式)

参考AOF的重写机制,可以很好的理解混合持久化方式。

上述的第三步,改成以RDB的方式写入全量数据(而不是redis格式的指令),再增加增量数据。这样既可以提高重写和恢复速度,又可以减小文件大小,还可以保证数据的完整性。

因此混合持久化方式:子进程在做AOF重写时,会通过管道从主进程读取增量数据并缓存,再以RDB方式保存全量数据时,也会从管道读取数据。所以AOF的文件前半部分是RDB格式的全量数据,后半部分是redis格式的增量数据。

BGSAVE做镜像全量持久化(redis重启时,BGSAVE的持久化重构内容,AOF重放近期的redis指令,实现完整恢复),AOF做增量持久化(解决停机时数据大量丢失问题)。

七、Pipeline及主从同步

7.1 Pipeline的简介

  • 1.Pipeline和Linux的管道类似
  • 2.Redis基于请求/响应模型,单个请求处理需要一一应答。
  • 3.Pipeline批量执行指令,节省多次I/O往返的时间。允许客户端一次发送多条命令,不需要等待上一条命令执行的结果。客户端首先将需要执行的命令写在缓存(例如,实例tmpTest.txt)中,然后一次性发送给redis,因此通过pipeline可以将多次的I/O往返请求缩减为一次。
  • 4.有顺序依赖的指令建议分批发送。

7.2 redis的同步机制

解决如下问题:
1.如何配置redis的主从同步?
2.如何配置redis的哨兵?
3.如何配置redis的集群?

7.3 redis的主从同步原理


redis集群中,一般是有一个master进行写操作、若干个sliver进行读操作,定期的备份操作也是(随机)选择一个sliver进行的,以便最大程度发挥redis的性能,为的是让其支持数据的最终一致性,不需要实时的保证master和sliver之间的数据是同步的,但是一定是趋于同步的。

redis可以使用主从同步和从从同步。第一次同步时,主节点做一次全量bgsave生产RDB文件,后续的增量操作记录在内存的buff中。待bgsave完成后,将RDB文件全量同步到从节点中,从节点将镜像全量加载到内存中,加载完成后,再通知主节点,将该期间的增量数据同步到从节点进行重放,从而完成同步过程。

7.4 全同步过程

  • 1.从节点发送sync命令到主节点
  • 2.主节点fork一个子进程,将redis中的数据快照保存到文件中,即进行bgsave操作。
  • 3.主节点将bgsave期间接受到的写命令进行缓存,即保存增量数据。
  • 4.主节点完成bgsave后,将该RDB文件发送给从节点。
  • 5.从节点使用新的RDB文件替换掉久的RDB文件。
  • 6.主节点将这期间收集的增量写命令发送给从节点进行回放,完成同步过程。

7.5 增量同步过程

为了提升性能,一般写操作都是在主节点进行、读操作在从节点进行,因此用户的写操作必须及时扩散到从节点,保证最大限度的同步。

  • 1.主节点接收到用户的操作指令(读指令不需要传播),判断是否需要传播到从节点。
  • 2.将操作记录最佳到AOF文件。
  • 3.将操作传播到其他的从节点:
    • 对齐主从库,确保从数据库是该操作对应的数据库。
    • 将命令和参数按照redis的命令格式写入到响应缓存中。
  • 4.将缓存中俄数据发送给slave。

7.6 redis sentinel(redis哨兵)

redis主从同步的弊端,主节点宕机后,无法对外提供写入操作,redis sentinel(redis哨兵)可以使用主从切换解决该问题。

  • 1.监控,检查主从服务器是否运行正常
  • 2.提醒,通过API向管理员或者其他应用程序发送故障通知
  • 3.自动故障迁移,主从切换(将宕机的主节点中的一个从节点升级为新的主节点,让其他的从节点识别新的主节点,进行主从同步,并向正在请求主节点的客户端返回新主节点的地址,保证集群的正常运行)。

redis sentinel是分布式系统,在集群中可以运行多个redis sentinel进程,这些进程使用流言协议(Gossip)来接收主节点是否下线的通知和发现新节点,使用投靠协议决定是否执行自动故障迁移和选择哪一个从节点升级为新的主节点。

7.7 流言协议Gossip

Gossip算法又被称为反熵算法,即在杂乱无章中寻求一致。

  • 1.每个节点都随机地与对方通信,最终所有节点的状态达成一致。
  • 2.种子节点定期随机向其他节点发送节点列表以及需要传播的消息。
  • 3.不保证信息一定会传递给所有节点,但是最终会趋于一致。

八、redis集群

集群技术是构建高性能网站架构的重要手段,redis集群采用无中心结构,每个节点都保存数据和整个集群的状态,每个节点都和其他节点进行连接,通过Gossip协议传递信息。集群的主要目的是将不同的key分散放置在不同的redis节点。

8.1 实现原理

按照常规做法,获取key的hash值,然后通过节点数求模,但是有弊端,无法实现节点的动态增减。因此可以使用一致性hash算法。

1.减去结点:

如果圆环上的一个结点上的redis服务器宕机,该节点上的新增的数据会存储到下一个结点上的redis,而受此影响的数据仅仅只有该结点到上一个结点之间的数据。

2.增加结点:
如果圆环上新增一台redis服务器,而受此影响的数据仅仅只有该新增结点到上一个结点之间的数据。

8.2 如何从海量数据里快速找到所需

  • 1.分片,按照某种规则去划分数据,分散存储在多个redis节点上,通过分片操作可以降低某些redis节点的压力。
  • 2.一致性hash算法,对2^32取模,将hash值空间组织成虚拟的圆环。
    • 假设某hash函数h的值空间为0~2^32-1,即hash值是一个32位的无符号整型。
    • 将redis服务器(ip、主机名等)进行hash的变换,确定redis服务器在hash圆环上的位置。
    • 将数据key使用相同的函数hash计算出hash值,顺时针最近的结点,确定此数据在hash环上的位置,进行分散存储。
  • 3.对于节点的增减,影响的只有一小部分数据,因此具有较好的容错性。

8.4 hash环的数据倾斜问题

当节点很少时,容易出现数据倾斜问题,即大量的缓存数据集中在某一台redis服务器上。如下图所示:

可以引入虚拟结点解决数据倾斜问题,即对于一个redis服务器计算多个hash值,在该hash值对应的圆环上加入虚拟结点。数据定位算法不变,只是多了一步,数据从虚拟结点到实际结点的映射。还可以引入主从同步、redis哨兵等技术,确保集群的高可用性。

最后修改于时间:2020年10月15日

最全redis缓存核心知点(原理+图解)相关推荐

  1. redis cluster 集群 HA 原理和实操(史上最全、面试必备)

    文章很长,建议收藏起来慢慢读!疯狂创客圈总目录 语雀版 | 总目录 码云版| 总目录 博客园版 为您奉上珍贵的学习资源 : 免费赠送 经典图书:<Java高并发核心编程(卷1)> 面试必备 ...

  2. Redis综述篇:与面试官彻夜长谈Redis缓存、持久化、淘汰机制、哨兵、集群底层原理!...

    点击上方关注 "终端研发部" 设为"星标",和你一起掌握更多数据库知识 于哥你好,最近面试挺多的,尤其是在问到java面试题,Redis被问的特别多,比如Red ...

  3. redis缓存实现原理php,分析redis原理及实现

    下面由Redis教程栏目给大家介绍分析redis原理及实现,希望对需要的朋友有所帮助! 1 什么是redis redis是nosql(也是个巨大的map) 单线程,但是可处理1秒10w的并发(数据都在 ...

  4. Redis缓存设计原理及实战

    缓存是什么? 一个系统中的不同层之间的访问速度不一样,所以我们才需要缓存,这样就可以把一些需要频繁访问的数据放在缓存中,以加快它们的访问速度. 为了让你能更好地理解,我以计算机系统为例,来解释一下.下 ...

  5. 利用Redis进行全页面缓存的简单Demo

    2019独角兽企业重金招聘Python工程师标准>>> 使用Redis进行全页面缓存,如何实现呢?本文使用简单的思路来实现这个功能. 一.环境介绍 使用的开源框架主要是springm ...

  6. springboot mybatis ehcache_SpringBoot入门建站全系列(十四)集成Redis缓存

    SpringBoot入门建站全系列(十四)集成Redis缓存 一.概述 本地缓存,就是使用应用内使用本地内存将数据暂缓存储,一般数据库的查询如果不怎么改动,可以用本地缓存暂存. 远程缓存,比如redi ...

  7. springsession原理及redis缓存处理

    1 Redis 中数据 通过springsession存储了用户的session数据,如下: "spring:session:expirations:1634214780000" ...

  8. redis缓存原理与实现_SpringBoot整合Redis缓存,手把手教你一步一步实现

    推荐学习 分布式大全:反向代理/Redis/中间件/MySQL/消息,挑战阿里P7必备 都是"Redis惹的祸",害我差点挂在美团三面,真是"虚惊一场" 微服务 ...

  9. 「中间件系列二」redis缓存

    Redis(Remote Dictionary Server) 是一个使用 C 语言编写的,开源的(BSD许可)高性能非关系型(NoSQL)的键值对数据库. Redis 可以存储键和五种不同类型的值之 ...

最新文章

  1. 每天学习Linux(3)---pwd命令
  2. Linux命令--pwd
  3. 实现一个反向传播人工神经网络
  4. DCMTK:DSRDocumentTree,DSRDocumentSubTree,DSRDocumentTreeNode和DSRContentItem类的测试程序
  5. php投票系统报告,投票系统设计
  6. Coding WebIDE 开放支持第三方 Git 仓库
  7. java中如何进入代码块_Java中的匿名代码块
  8. 常用的分析方法论及分析框架
  9. 华为携西班牙电信于智利设立NB-IoT开放实验室
  10. 《VoIP技术构架(第2版·修订版)》一1.4 语音与数据网合二为一的驱动力
  11. 哈尔滨工程大学 Beamer模板(LaTeX幻灯模板)
  12. oracle userenv('language'),USERENV()获取Oracle环境信息
  13. python另存为对话框_python – 另存为文件对话框 – 如何不允许覆盖
  14. Amdahl 定律详解
  15. 西数USB硬盘 WD10JMVW-11AJGS 4数据恢复步骤
  16. 软件测试学习笔记(二)软件测试基本技术
  17. javaScript基础面试题 --数据类型和考题
  18. 基于卷积神经网络的近红外夜间道路行人识别
  19. logit回归模型假设_机器学习基础---逻辑回归(假设函数与线性回归不同)
  20. java特粗宋体_Java IdentityPlusMapper类代码示例

热门文章

  1. GDC2016【全境封锁(Tom Clancy's The Division)】对为何对应Eye Tracked System,以及各种优点的演讲报告...
  2. 这波行情到什么时候结束,美人肩龙头股告诉你!
  3. php中css样式两端对齐,CSS两端对齐
  4. 两端对齐的css,CSS两端对齐(示例代码)
  5. 希捷3T硬盘松下mov变0字节视频恢复修复方法
  6. C++ switch用法
  7. 连锁便利店好邻居引入旷视科技投资 估值达2亿美元
  8. PICT用例设计工具介绍
  9. Linux删除软连接
  10. Android studio安装app时报错 Error: Activity class {} does not exist