分布式缓存——Redis高级彻底搞懂(Redis原理+主从+集群)
-- 基于Redis集群解决单机Redis存在的问题
一、Redis持久化
Redis有两种持久化方案:
- RDB持久化
- AOF持久化
1、RDB持久化
RDB全称Redis Database Backup file(Redis数据备份文件),也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后,从磁盘读取快照文件,恢复数据。快照文件称为RDB文件,默认是保存在当前运行目录。
1.1 执行机制
RDB持久化在四种情况下会执行:
- 执行save命令
- 执行bgsave命令
- Redis停机时
- 触发RDB条件时
1)save命令
执行下面的命令,可以立即执行一次RDB:
save命令会导致主进程执行RDB,这个过程中其它所有命令都会被阻塞。只有在数据迁移时可能用到。
2)bgsave命令
下面的命令可以异步执行RDB:
这个命令执行后会开启独立进程完成RDB,主进程可以持续处理用户请求,不受影响。
3)停机时
Redis停机时会执行一次save命令,实现RDB持久化。
4)触发RDB条件
Redis内部有触发RDB的机制,可以在redis.conf文件中找到,格式如下:
# 900秒内,如果至少有1个key被修改,则执行bgsave , 如果是save "" 则表示禁用RDB
save 900 1
save 300 10
save 60 10000
RDB的其它配置也可以在redis.conf文件中设置:
# 是否压缩 ,建议不开启,压缩也会消耗cpu,磁盘的话不值钱
rdbcompression yes# RDB文件名称
dbfilename dump.rdb # 文件保存的路径目录
dir ./
1.2 RDB原理
bgsave开始时会fork主进程得到子进程,子进程共享主进程的内存数据。完成fork后读取内存数据并写入 RDB 文件。
fork采用的是copy-on-write技术:
- 当主进程执行读操作时,访问共享内存;
- 当主进程执行写操作时,则会拷贝一份数据,执行写操作。
1.3 总结
RDB方式bgsave的基本流程?
- fork主进程得到一个子进程,共享内存空间
- 子进程读取内存数据并写入新的RDB文件
- 用新RDB文件替换旧的RDB文件
RDB会在什么时候执行?save 60 1000代表什么含义?
- 默认是服务停止时
- 代表60秒内至少执行1000次修改则触发RDB
RDB的缺点?
- RDB执行间隔时间长,两次RDB之间写入数据有丢失的风险
- fork子进程、压缩、写出RDB文件都比较耗时
2、AOF持久化
2.1 AOF原理
AOF全称为Append Only File(追加文件)。Redis处理的每一个写命令都会记录在AOF文件,可以看做是命令日志文件。
2.2 AOF配置
AOF默认是关闭的,需要修改redis.conf配置文件来开启AOF:
# 是否开启AOF功能,默认是no
appendonly yes
# AOF文件的名称
appendfilename "appendonly.aof"
AOF的命令记录的频率也可以通过redis.conf文件来配:
# 表示每执行一次写命令,立即记录到AOF文件
appendfsync always
# 写命令执行完先放入AOF缓冲区,然后表示每隔1秒将缓冲区数据写到AOF文件,是默认方案
appendfsync everysec
# 写命令执行完先放入AOF缓冲区,由操作系统决定何时将缓冲区内容写回磁盘
appendfsync no
三种策略对比:
2.3 AOF文件重写
因为是记录命令,AOF文件会比RDB文件大的多。而且AOF会记录对同一个key的多次写操作,但只有最后一次写操作才有意义。通过执行bgrewriteaof命令,可以让AOF文件执行重写功能,用最少的命令达到相同效果。
如图,AOF原本有三个命令,但是set num 123 和 set num 666
都是对num的操作,第二次会覆盖第一次的值,因此第一个命令记录下来没有意义。
所以重写命令后,AOF文件内容就是:mset name jack num 666
Redis也会在触发阈值时自动去重写AOF文件。阈值也可以在redis.conf中配置:
# AOF文件比上次文件 增长超过多少百分比则触发重写
auto-aof-rewrite-percentage 100
# AOF文件体积最小多大以上才触发重写
auto-aof-rewrite-min-size 64mb
3、RDB和AOF对比
RDB和AOF各有自己的优缺点,如果对数据安全性要求较高,在实际开发中往往会结合两者来使用。
二、Redis主从
1. 搭建主从架构
单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,就需要搭建主从集群,实现读写分离。
2. Redis主从搭建的过程本文不再赘述,博主将在新的文章中更新详细的搭建流程。
2、主从数据同步原理
2.1 全量同步
主从第一次建立连接时,会执行全量同步,将master节点的所有数据都拷贝给slave节点,流程:
这里有一个问题,master如何得知salve是第一次来连接呢??
有几个概念,可以作为判断依据:
Replication Id:简称replid,是数据集的标记,id一致则说明是同一数据集。每一个master都有唯一的replid,slave则会继承master节点的replid
offset:偏移量,随着记录在repl_baklog中的数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset。如果slave的offset小于master的offset,说明slave数据落后于master,需要更新。
因此slave做数据同步,必须向master声明自己的replication id 和offset,master才可以判断到底需要同步哪些数据。
因为slave原本也是一个master,有自己的replid和offset,当第一次变成slave,与master建立连接时,发送的replid和offset是自己的replid和offset。
master判断发现slave发送来的replid与自己的不一致,说明这是一个全新的slave,就知道要做全量同步了。
master会将自己的replid和offset都发送给这个slave,slave保存这些信息。以后slave的replid就与master一致了。
因此,master判断一个节点是否是第一次同步的依据,就是看replid是否一致。
如图:
完整流程描述:
- slave节点请求增量同步
- master节点判断replid,发现不一致,拒绝增量同步
- master将完整内存数据生成RDB,发送RDB到slave
- slave清空本地数据,加载master的RDB
- master将RDB期间的命令记录在repl_baklog,并持续将log中的命令发送给slave
- slave执行接收到的命令,保持与master之间的同步
2.2 增量同步
全量同步需要先做RDB,然后将RDB文件通过网络传输个slave,成本太高了。因此除了第一次做全量同步,其它大多数时候slave与master都是做增量同步。
什么是增量同步?就是只更新slave与master存在差异的部分数据。如图:
2.3 repl_backlog原理
master怎么知道slave与自己的数据差异在哪里呢?
这就要说到全量同步时的repl_baklog文件了。
这个文件是一个固定大小的数组,只不过数组是环形,也就是说角标到达数组末尾后,会再次从0开始读写,这样数组头部的数据就会被覆盖。
repl_baklog中会记录Redis处理过的命令日志及offset,包括master当前的offset,和slave已经拷贝到的offset:
slave与master的offset之间的差异,就是salve需要增量拷贝的数据了。
随着不断有数据写入,master的offset逐渐变大,slave也不断的拷贝,追赶master的offset:
2.3 主从同步优化
主从同步可以保证主从数据的一致性,非常重要。
可以从以下几个方面来优化Redis主从就集群:
在master中配置repl-diskless-sync yes启用无磁盘复制,避免全量同步时的磁盘IO。
Redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘IO
适当提高repl_baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步
限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结构,减少master压力
主从从架构图:
2.4 总结
简述全量同步和增量同步区别?
- 全量同步:master将完整内存数据生成RDB,发送RDB到slave。后续命令则记录在repl_baklog,逐个发送给slave。
- 增量同步:slave提交自己的offset到master,master获取repl_baklog中从offset之后的命令给slave
什么时候执行全量同步?
- slave节点第一次连接master节点时
- slave节点断开时间太久,repl_baklog中的offset已经被覆盖时
什么时候执行增量同步?
- slave节点断开又恢复,并且在repl_baklog中能找到offset时
三、Redis哨兵
Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。
1、哨兵原理
1.1 集群结构和作用
哨兵的作用如下:
- 监控:Sentinel 会不断检查您的master和slave是否按预期工作
- 自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主
- 通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端
1.2 集群监控原理
Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令:
- •主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线。
- •客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel实例数量的一半。
1.3 集群故障恢复原理
一旦发现master故障,sentinel需要在salve中选择一个作为新的master,选择依据是这样的:
- 首先会判断slave节点与master节点断开时间长短,如果超过指定值(down-after-milliseconds * 10)则会排除该slave节点
- 然后判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举
- 如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高
- 最后是判断slave节点的运行id大小,越小优先级越高。
当选出一个新的master后,该如何实现切换呢?
流程如下:
- sentinel给备选的slave1节点发送slaveof no one命令,让该节点成为master
- sentinel给所有其它slave发送slaveof 192.168.150.101 7002 命令,让这些slave成为新master的从节点,开始从新的master上同步数据。
- 最后,sentinel将故障节点标记为slave,当故障节点恢复后会自动成为新的master的slave节点
1.4 总结
Sentinel的三个作用是什么?
- 监控
- 故障转移
- 通知
Sentinel如何判断一个redis实例是否健康?
- 每隔1秒发送一次ping命令,如果超过一定时间没有相向则认为是主观下线
- 如果大多数sentinel都认为实例主观下线,则判定服务下线
故障转移步骤有哪些?
- 首先选定一个slave作为新的master,执行slaveof no one
- 然后让所有节点都执行slaveof 新master
- 修改故障节点配置,添加slaveof 新master
2、搭建哨兵集群
*Redis主从搭建的过程本文不再赘述,博主将在新的文章中更新详细的搭建流程。
3、RedisTemplate
在Sentinel集群监管下的Redis主从集群,其节点会因为自动故障转移而发生变化,Redis的客户端必须感知这种变化,及时更新连接信息。Spring的RedisTemplate底层利用lettuce实现了节点的感知和自动切换。
下面,我们通过一个测试来实现RedisTemplate集成哨兵机制。
2.1 首先,引入博主在下载资料中提供的demo案例文件。
2.2 引入依赖
在项目的pom文件中引入依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.3 配置Redis地址
然后在配置文件application.yml中指定redis的sentinel相关信息:
spring:redis:sentinel:master: mymasternodes:- 192.168.150.101:27001- 192.168.150.101:27002- 192.168.150.101:27003
2.4 配置读写分离
在项目的启动类中,添加一个新的bean:
@Bean
public LettuceClientConfigurationBuilderCustomizer clientConfigurationBuilderCustomizer(){return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}
这个bean中配置的就是读写策略,包括四种:
- MASTER:从主节点读取
- MASTER_PREFERRED:优先从master节点读取,master不可用才读取replica
- REPLICA:从slave(replica)节点读取
- REPLICA _PREFERRED:优先从slave(replica)节点读取,所有的slave都不可用才读取master
四、Redis分片集群
1、搭建分片集群
主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决:
- 海量数据存储问题
- 高并发写的问题
使用分片集群可以解决上述问题,如图:
分片集群特征:
- 集群中有多个master,每个master保存不同数据
- 每个master都可以有多个slave节点
- master之间通过ping监测彼此健康状态
- 客户端请求可以访问集群任意节点,最终都会被转发到正确节点
2、Redis分片集群搭建
* Redis分片集群搭建的过程本文不再赘述,博主将在新的文章中更新详细的搭建流程。
3、散列插槽
Redis会把每一个master节点映射到0~16383共16384个插槽(hash slot)上,查看集群信息时就能看到:
数据key不是与节点绑定,而是与插槽绑定。redis会根据key的有效部分计算插槽值,分两种情况:
- key中包含"{}",且“{}”中至少包含1个字符,“{}”中的部分是有效部分
- key中不包含“{}”,整个key都是有效部分
例如:key是num,那么就根据num计算,如果是{itcast}num,则根据itcast计算。计算方式是利用CRC16算法得到一个hash值,然后对16384取余,得到的结果就是slot值。
如图,在7001这个节点执行set a 1时,对a做hash运算,对16384取余,得到的结果是15495,因此要存储到103节点。
到了7003后,执行get num
时,对num做hash运算,对16384取余,得到的结果是2765,因此需要切换到7001节点
3.1 总结:
Redis如何判断某个key应该在哪个实例?
- 将16384个插槽分配到不同的实例
- 根据key的有效部分计算哈希值,对16384取余
- 余数作为插槽,寻找插槽所在实例即可
如何将同一类数据固定的保存在同一个Redis实例?
- 这一类数据使用相同的有效部分,例如key都以{typeId}为前缀
4、集群伸缩
redis-cli --cluster提供了很多操作集群的命令,可以通过下面方式查看:
比如,添加节点的命令:
4.1 案例:需求分析
需求:向集群中添加一个新的master节点,并向其中存储 num = 10
- 启动一个新的redis实例,端口为7004
- 添加7004到之前的集群,并作为一个master节点
- 给7004节点分配插槽,使得num这个key可以存储到7004实例
这里需要两个新的功能:
- 添加一个节点到集群中
- 将部分插槽分配到新插槽
4.2 创建新的redis实例
创建一个文件夹:
mkdir 7004
拷贝配置文件:
cp redis.conf /7004
修改配置文件:
sed /s/6379/7004/g 7004/redis.conf
启动:
redis-server 7004/redis.conf
4.3 添加新节点到redis![](/assets/blank.gif)
4.4 转移插槽
这里询问,你的插槽是从哪里移动过来的?
- all:代表全部,也就是三个节点各转移一部分
- 具体的id:目标节点的id
- done:没有了
4.5 故障转移
4.5.1 自动故障转移
4.5.2 手动故障zhaun yi
利用cluster failover命令可以手动让集群中的某个master宕机,切换到执行cluster failover命令的这个slave节点,实现无感知的数据迁移。其流程如下:
这种failover命令可以指定三种模式:
- 缺省:默认的流程,如图1~6歩
- force:省略了对offset的一致性校验
- takeover:直接执行第5歩,忽略数据一致性、忽略master状态和其它master的意见
4.6 RedisTeplate访问分片集群![](/assets/blank.gif)
五、企业级解决方案
1、预热缓存
“宕机”
服务器启动后迅速宕机
问题排查
- 请求数量较高
- 主从之间数据吞吐量较大,数据同步操作频度较高
解决方案
前置准备工作:
- 日常例行统计数据访问记录,统计访问频度较高的热点数据
- 利用LRU数据删除策略,构建数据留存队列
例如:storm与kafka配合 准备工作
准备工作:
- 将统计结果中的数据分类,根据级别,redis优先加载级别较高的热点数据
- 利用分布式多服务器同时进行数据读取,提速数据加载过程
- 热点数据主从同时预热
实施:
- 使用脚本程序固定触发数据预热过程
- 如果条件允许,使用了CDN(内容分发网络),效果会更好
缓存预热就是系统启动前,提前将相关的缓存数据直接加载到缓存系统。避免在用户请求的时候,先查询数据库,然后再将数 据缓存的问题!用户直接查询事先被预热的缓存数据!
2、缓存雪崩
数据库服务器崩溃(1)
系统平稳运行过程中,忽然数据库连接量激增
应用服务器无法及时处理请求
大量408,500错误页面出现
客户反复刷新页面获取数据
数据库崩溃
应用服务器崩溃
重启应用服务器无效
Redis服务器崩溃
Redis集群崩溃
重启数据库后再次被瞬间流量放倒
问题排查
在一个较短的时间内,缓存中较多的key集中过期
此周期内请求访问过期的数据,redis未命中,redis向数据库获取数据
数据库同时接收到大量的请求无法及时处理
Redis大量请求被积压,开始出现超时现象
数据库流量激增,数据库崩溃
重启后仍然面对缓存中无数据可用
Redis服务器资源被严重占用,Redis服务器崩溃
Redis集群呈现崩塌,集群瓦解
应用服务器无法及时得到数据响应请求,来自客户端的请求数量越来越多,应用服务器崩溃
应用服务器,redis,数据库全部重启,效果不理想
问题分析
⚫ 短时间范围内
⚫ 大量key集中过期
解决方案(道)
更多的页面静态化处理
构建多级缓存架构
Nginx缓存+redis缓存+ehcache缓存
检测Mysql严重耗时业务进行优化 对数据库的瓶颈排查:例如超时查询、耗时较高事务等
灾难预警机制
监控redis服务器性能指标
⚫ CPU占用、CPU使用率
⚫ 内存容量
⚫ 查询平均响应时间
⚫ 线程数
限流、降级
短时间范围内牺牲一些客户体验,限制一部分请求访问,降低应用服务器压力,待业务低速运转后再逐步放开访问
解决方案(术)
LRU与LFU切换
数据有效期策略调整
⚫ 根据业务数据有效期进行分类错峰,A类90分钟,B类80分钟,C类70分钟
⚫ 过期时间使用固定时间+随机值的形式,稀释集中到期的key的数量 3.
超热数据使用永久key 4.
定期维护(自动+人工)
对即将过期数据做访问量分析,确认是否延时,配合访问量统计,做热点数据的延时
加锁
慎用!
缓存雪崩就是瞬间过期数据量太大,导致对数据库服务器造成压力。如能够有效避免过期时间集中,可以有效解决雪崩现象的 出现(约40%),配合其他策略一起使用,并监控服务器的运行数据,根据运行记录做快速调整。
3、缓存击穿
数据库服务器崩溃(2)
系统平稳运行过程中
数据库连接量瞬间激增
Redis服务器无大量key过期
Redis内存平稳,无波动
Redis服务器CPU正常
数据库崩溃
问题排查
Redis中某个key过期,该key访问量巨大
多个数据请求从服务器直接压到Redis后,均未命中
Redis在短时间内发起了大量对数据库中同一数据的访问
问题分析
⚫ 单个key高热数据
⚫ key过期
解决方案(术)
预先设定
以电商为例,每个商家根据店铺等级,指定若干款主打商品,在购物节期间,加大此类信息key的过期时长
注意:购物节不仅仅指当天,以及后续若干天,访问峰值呈现逐渐降低的趋势
现场调整
监控访问量,对自然流量激增的数据延长过期时间或设置为永久性key
后台刷新数据
启动定时任务,高峰期来临之前,刷新数据有效期,确保不丢失
二级缓存
设置不同的失效时间,保障不会被同时淘汰就行
加锁
分布式锁,防止被击穿,但是要注意也是性能瓶颈,慎重!
缓存击穿就是单个高热数据过期的瞬间,数据访问量较大,未命中redis后,发起了大量对同一数据的数据库访问,导致对数 据库服务器造成压力。应对策略应该在业务数据分析与预防方面进行,配合运行监控测试与即时调整策略,毕竟单个key的过 期监控难度较高,配合雪崩处理策略即可。
4、缓存穿透
数据库服务器崩溃(3)
系统平稳运行过程中
应用服务器流量随时间增量较大
Redis服务器命中率随时间逐步降低
Redis内存平稳,内存无压力
Redis服务器CPU占用激增
数据库服务器压力激增
数据库崩溃
问题排查
Redis中大面积出现未命中
出现非正常URL访问
问题分析
⚫ 获取的数据在数据库中也不存在,数据库查询未得到对应数据
⚫ Redis获取到null数据未进行持久化,直接返回
⚫ 下次此类数据到达重复上述过程
⚫ 出现黑客攻击服务器
解决方案(术)
缓存null 对查询结果为null的数据进行缓存(长期使用,定期清理),设定短时限,例如30-60秒,最高5分钟
白名单策略
⚫ 提前预热各种分类数据id对应的bitmaps,id作为bitmaps的offset,相当于设置了数据白名单。当加载正常数据时 放行,加载异常数据时直接拦截(效率偏低)
⚫ 使用布隆过滤器(有关布隆过滤器的命中问题对当前状况可以忽略)
实施监控 实时监控redis命中率(业务正常范围时,通常会有一个波动值)与null数据的占比
⚫ 非活动时段波动:通常检测3-5倍,超过5倍纳入重点排查对象
⚫ 活动时段波动:通常检测10-50倍,超过50倍纳入重点排查对象 根据倍数不同,启动不同的排查流程。然后使用黑名单进行防控(运营)
key加密
问题出现后,临时启动防灾业务key,对key进行业务层传输加密服务,设定校验程序,过来的key校验 例如每天随机分配60个加密串,挑选2到3个,混淆到页面数据id中,发现访问key不满足规则,驳回数据访问
缓存击穿访问了不存在的数据,跳过了合法数据的redis数据缓存阶段,每次访问数据库,导致对数据库服务器造成压力。通 常此类数据的出现量是一个较低的值,当出现此类情况以毒攻毒,并及时报警。应对策略应该在临时预案防范方面多做文章。 无论是黑名单还是白名单,都是对整体系统的压力,警报解除后尽快移除
分布式缓存——Redis高级彻底搞懂(Redis原理+主从+集群)相关推荐
- 快速搞懂Docker部署ElasticSearch集群
前言 为什么要用ElasticSearch?我们的应用经常需要添加检索功能,开源的Elastic Search是目前全文检索引擎的首选.它可以快速的存储.搜索和分析海量数据.ElasticSearch ...
- 云图说 | 分布式缓存服务DCS—站在开源Redis前辈的肩膀上,扬帆起航
阅识风云是华为云信息大咖,擅长将复杂信息多元化呈现,其出品的一张图(云图说).深入浅出的博文(云小课)或短视频(云视厅)总有一款能让您快速上手华为云.更多精彩内容请单击此处. 摘要:DCS基于开源Re ...
- 12 个问题搞懂 Redis
都说学习需要带着问题,带着思考进行学习,下面就以问题的形式来学习下 Redis . 1.什么是 Redis ? Redis 是一个高性能的 key-value 数据库: 作者来自意大利西西里岛的 Sa ...
- 大厂都咋用平台、分布式缓存?起码你要懂技术,高级还得懂业务
所有程序猿都对那缓存并不陌生,好似那风一样的女子只为你独自而舞.只见那回眸一笑百媚生,让你甚是吝惜,惹人怜爱. 但随着项目规模不断增大变强,光是单个缓存就难以招架,优而显得力不从心. 这时伴随着多级缓 ...
- JavaScript高级 |彻底搞懂原型对象
本文已收录于专栏 ⭐️ <JavaScript>⭐️ 学习指南: 对象的原型 函数的原型 new操作符 将方法放原型里 constructor 总结梳理 原型对象 内存表现 完结散花 参考 ...
- 面试精讲之面试考点及大厂真题 - 分布式专栏 09 缓存必问:Reids持久化,高可用集群
09缓存必问:Reids持久化,高可用集群 宝剑锋从磨砺出,梅花香自苦寒来. 引言 Redis 的优点中提到 Redis 支持持久化数据,宕机后可恢复数据,持久化就是基于内存读写的 Redis 数据一 ...
- Redis 主从集群搭建及哨兵模式配置
Redis 主从集群搭建及哨兵模式配置 最近搭建了redis集群及哨兵模式,为方便以后查看特此记录下来: 1.Redis安装 2.主从架构 2.1 Redis主从架构图 2.2Redis主从结构搭建 ...
- Redis高可用——主从复制、哨兵模式、集群
文章目录 一.Redis高可用 1.什么是高可用 2.Redis的高可用技术 二.Redis主从复制 1.Redis主从复制的作用 2.主从复制的流程 三.主从复制的搭建 实验准备 1.所有主机安装R ...
- Redis实践(二)高可用的集群+哨兵部署
项目中通常会需要若干台Redis服务器来协同担当起内存数据库的工作,在redis的部署方案上要考虑下面几点: 结构上,单个 Redis 服务器会发生单点故障,而且一台服务器需要承受所有的请求负载. 这 ...
最新文章
- Linux内核模块编程系列1-极简内核模块编写
- 企业生产过程中的日志和时间管理详解
- 【ORACLE】oracl基本操作笔记
- doctype的种类
- Python基础之:struct和格式化字符
- mysql 官方镜像_运行官方mysql 镜像
- 【LeetCode - 224】基本计算器(栈)
- 自考的那些事儿(二):第二次自考完了???
- Bailian2929 扩号匹配【堆栈】
- 免费下载谷歌maps软件_Android Google Maps示例教程
- Pads logic 创建文件时发生严重错误
- 114. PHP command line getopt
- SECS I II HSMS 和GEM初步资料总结
- linux 下修改文件夹的用户权限和所属组,为文件建立软连接
- java中object是什么_Java中的Object是什么?
- layuiadmin上手好难_滑步车比赛好拍吗?
- K8s 很难么?带你从头到尾捋一遍,不信你学不会
- 【数据结构】CH3 栈和队列
- 视频webm怎么转换成mp4
- 自己动手制作RPM包
热门文章
- 汽车动力转向系统的检修
- 如何培养高情商的孩子读后感
- akka mysql_Akka系列(七):Actor持久化之Akka persistence
- GC(1.安全点的相关知识)
- 咪咕盒子mg100/mg101_晶晨S905L-B处理器-无线6051P-CNTV牌照-当贝桌面-线刷固件包
- (原創) 如何將ThinkPad的『上一頁』和『下一頁』改成『PageUp』和『PageDn』? (NB) (ThinkPad) (OS) (Windows)...
- Python 爬虫实现:抓取电影网站信息并入库
- Hello Spring boot
- 深圳市弘辽科技:快速提高淘宝直通车关键词质量分的技巧
- 引文分析软件histcite简介