何谓持久化,就是媳妇让你,持久一些。

说白了持久化:就是将内存中的数据保存到磁盘上的过程(数据库也算磁盘的特殊表现),以保证宕机或断电后,可以继续访问。java中常见的持久化框架,如Hibernate,ibatis,jdbc都是持久化实现方式的一种,当然普通文件保存功能也算。

拿memcached来说,memcached保存的信息,没有进行持久化,所以只能存活一个进程生命期,下次重新启动,数据全部丢失。这算memcached的一个缺点吧。redis提供了持久化支持,而且提供了2种持久化方案。

《redis演练系列》,立足于案例展示,通过形象,对比,图示的方式,达到知识梳理过程。

本章的主要梗概。

  • redis两种持久化方案对比

  • redis两种持久化方案参数说明

  • 演练RDB的触发时机

  • 演练AOF

  • RDB VS AOF

1.redis两种持久化方案对比

redis提供了两种持久化的方式,分别是RDB(Redis DataBase)和AOF(Append Only File)。RDB,AOF就相当于redis持久界的2个亲兄弟,相互配合,相互提携。当然也会争抢些资源。
RDB,简而言之,就是在不同的时间点,将redis存储的数据生成快照并存储到磁盘等介质上;
AOF,则是换了一个角度来实现持久化,那就是将redis执行过的所有写指令记录下来,在下次redis重新启动时,只要把这些写指令从前到后再重复执行一遍,就可以实现数据恢复了。

RDB将服务器包含的所有数据库数据以二进制文件的形式保存到硬盘里面。

下图,是具体操作步骤。具体详情参见【http://www.cnblogs.com/luogankun/p/3986403.html】

AOF,英文是Append Only File,即只允许追加不允许改写的文件。AOF方式是将执行过的写指令记录下来,在数据恢复时按照从前到后的顺序再将指令都执行一遍,就这么简单。有点数据库软件联机日志的影子。

两者对比

redis两种持久化方案参数说明

涉及到文件保存,一般要考虑以下几个问题,不仅仅限于redis。

  • 保存时机:什么时候触发。取决于数据一致性和效率的平衡

  • 保存目标对象:日志,二进制...

  • 保存目录:本地目录,还是共享目录

  • 是否压缩:节省空间

  • 是否校验:考虑安全

  • 保存失败处理机制:异常报告

  • 开启线程数:决定速度,但会影响其他功能

  • 保存文件限制:超过大小,不允许;和不允许上传*.exe文件等

带着这些问题,去扣相关的RDB参数,和AOF参数,问题就简单多了。

RDB # 存 DB 到磁盘:
#
#   格式:save <间隔时间(秒)> <写入次数>
#
#   根据给定的时间间隔和写入次数将数据保存到磁盘
#
#   下面的例子的意思是:
#   900 秒后如果至少有 1 个 key 的值变化,则保存
#   300 秒后如果至少有 10 个 key 的值变化,则保存
#   60 秒后如果至少有 10000 个 key 的值变化,则保存
#
#   注意:你可以注释掉所有的 save 行来停用保存功能。
#   也可以直接一个空字符串来实现停用:
#   save ""

save 900 1
save 300 10
save 60 10000

# 默认情况下,如果 redis 最后一次的后台保存失败,redis 将停止接受写操作,
# 这样以一种强硬的方式让用户知道数据不能正确的持久化到磁盘,
# 否则就会没人注意到灾难的发生。
#
# 如果后台保存进程重新启动工作了,redis 也将自动的允许写操作。
#
# 然而你要是安装了靠谱的监控,你可能不希望 redis 这样做,那你就改成 no 好了。
stop-writes-on-bgsave-error yes

# 是否在 dump .rdb 数据库的时候使用 LZF 压缩字符串
# 默认都设为 yes
# 如果你希望保存子进程节省点 cpu ,你就设置它为 no ,
# 不过这个数据集可能就会比较大
rdbcompression yes

# 是否校验rdb文件
rdbchecksum yes

# 设置 dump 的文件位置
dbfilename dump.rdb

# 工作目录
# 例如上面的 dbfilename 只指定了文件名,
# 但是它会写入到这个目录下。这个配置项一定是个目录,而不能是文件名。
dir ./

AOF
    #默认情况下Redis会异步的将数据导出到磁盘上。这种模式对许多应用程序已经足够了,  
    #但是如果断电或者redis进程出问题就会导致一段时间内的更新数据丢失(取决与配置项)  
    #  
    #这种只增文件是可选的能够提供更好的体验的数据持久化策略。  
    #举个例子,如果使用默认的配置数据fsync策略,在服务器意外断电的情况下redis只会丢失一秒中内的更新数据,  
    #或者当redis进程出问题但操作系统运转正常时,redis只会丢失一个数据更新操作。  
    #  
    #AOF 和 RDB 持久化方式可以同时启动并且无冲突。  
    #如果AOF开启,启动redis时会加载aof文件,这些文件能够提供更好的保证。  
    #请在 http://redis.io/topics/persistence 获取更多数据持久化信息。  
      
    appendonly no  
      
    # 只增文件的文件名称。(默认是appendonly.aof)  
    # appendfilename appendonly.aof  
      
    #调用fsync()函数会通知操作系统真正将数据写入磁盘,而不是等待缓冲区中有更多数据。  
    #有些操作系统会将数据输出到磁盘,有些操作系统只是ASAP。  
    #  
    #redis支持三种不同的方式:  
    #  
    #no:不调用,之等待操作系统来清空缓冲区当操作系统要输出数据时。很快。  
    # always: 每次更新数据都写入仅增日志文件。慢,但是最安全。  
    # everysec: 每秒调用一次。折中。  
    #  
    #默认是每秒中一次,因为它往往是在速度和数据安全两者之间的折中选择。  
    #如果你可以接受让操作系统去自动清空缓存,你可以将这项配置降低到'no'(如果你可以接受一段时间的数据丢失,默认的rdb就足够了),  
    #这完全取决与你。如果你想要一个更好的体验或者从相反的角度,使用'always',这样会很慢,但是比'everysec'安全些。  
    #  
    #请在下面的文章中获取更多细节知识:  
    #  http://antirez.com/post/redis-persistence-demystified.html  
    #  
    #如果你不是很清楚这三项之间的区别,或者不知道哪种适合你的机器,就是用默认吧。  
      
    # appendfsync always

appendfsync everysec

# appendfsync no

#当AOF策略设置为'always'或者'everysec'的时候,后台的保存进程会进行很多磁盘I/O操作,  
    #在某些linux结构中redis会在调用sync()方法时阻塞很长时间。记住,现在还没办法解决这个问题,即使在不同进程中进行调用也会block。  
    #  
    #使用如下配置可能会缓解这个问题,这样会在存储大数据或者BIGREWRITEAOF的时候不会在主进程中调用fsync()方法。  
    #  
    # 这表示,如果另外一个子进程在进行保存操作,redis的表现如同配置为‘appendfsync no’。  
    #在实际应用中,这表示在最坏的情景下(使用linux默认配置)可能会丢失30秒日志。  
    #   
    #如果你有特殊的情况可以配置为'yes'。但是配置为'no'是最为安全的选择。  
    no-appendfsync-on-rewrite no  
      
      
    #自动重写只增文件。  
    #redis可以自动盲从的调用‘BGREWRITEAOF’来重写日志文件,如果日志文件增长了指定的百分比。  
    #   
    #它是这样工作的:每次rewrite后redis会记录日志文件的大小。(如果重启后没有重写后的大小,就默认用日志文件大小)  
    #  
    # 这个基准日志大小和当前日志大小做比较。如果当前大小比指定的百分比,重写机制就会被触发。  
    #同时,你也要制定一个重写下线,用来避免增长百分比够了,但是日志文件还很小的情况。  
    #  
    #指定百分比为0可以注掉自动重写日志文件功能。        
    auto-aof-rewrite-percentage 100

auto-aof-rewrite-min-size 64mb

#redis在启动的时候可以加载被截断的AOF文件,默认启用;    (3.0以后才支持)

aof-load-truncated yes

2.演练RDB的触发时机

#   900 秒后如果至少有 1 个 key 的值变化,则保存
#   300 秒后如果至少有 10 个 key 的值变化,则保存
#   60 秒后如果至少有 10000 个 key 的值变化,则保存
#   注意:你可以注释掉所有的 save 行来停用保存功能。
#   也可以直接一个空字符串来实现停用:
#   save ""
save 900 1
save 300 10
save 60 10000

采用默认的RDB配置

redis.conf

1
2
3
4
5
6
7
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
dbfilename dump.rdb
dir ./

2.1演练“重启redis,键值丢失”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@hadoop2 redis]# bin/redis-cli  -h  192.168.163.156
192.168.163.156:6379> flushdb
OK
192.168.163.156:6379> set blog "blog.51cto.com"
OK
#为键赋值
192.168.163.156:6379> get blog
"blog.51cto.com"
192.168.163.156:6379> exit
[root@hadoop2 redis]# ps -ef |grep redis
root      2546     1  0 07:42 ?        00:00:05 /usr/local/redis/bin/redis-server 192.168.163.156:6379       
root      3235  2517  0 08:54 pts/0    00:00:00 grep redis
[root@hadoop2 redis]# kill -9 2546
#重启redis
[root@hadoop2 redis]# bin/redis-server  redis.conf 
[root@hadoop2 redis]# bin/redis-cli  -h  192.168.163.156
# blog键值丢失
192.168.163.156:6379> get blog
(nil)

这个结果,是不是非常出人意外。看来“江湖上都传言,redis断电键值不丢失”有点问题。

其实,没问题。是上面的演练存在不足,数据量没有达到触发时机要求。继续。

2.2演练“重启redis,键值不丢失”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[root@hadoop2 redis]# bin/redis-cli  -h  192.168.163.156
192.168.163.156:6379> set blog "blog.51cto.com"
OK
#借助自带测试工具,发送1w请求,触发RDB保存
[root@hadoop2 redis]# bin/redis-benchmark  -r 10000 -h 192.168.163.156
====== PING_INLINE ======
  100000 requests completed in 0.83 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1
99.77% <= 1 milliseconds
...
# 确认  键值还存在
[root@hadoop2 redis]# bin/redis-cli  -h  192.168.163.156
192.168.163.156:6379> get blog
"blog.51cto.com"
192.168.163.156:6379> exit
#关闭 redis服务
[root@hadoop2 redis]# ps -ef |grep redis
root      3241     1  3 08:54 ?        00:00:19 bin/redis-server 192.168.163.156:6379
root      3351  2517  0 09:05 pts/0    00:00:00 grep redis
[root@hadoop2 redis]# kill -9 3241
#重启redis服务
[root@hadoop2 redis]# bin/redis-server  redis.conf 
#确认重启后,blog键值依然存在
[root@hadoop2 redis]# bin/redis-cli  -h  192.168.163.156
192.168.163.156:6379> get blog
"blog.51cto.com"

看来“江湖上都传言,redis断电键值不丢失”,是有前提条件的。

3.演练AOF

修改redis.conf 开启AOF 关闭RDB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
save 900 1
save 300 10
save 60 10000
save ""
stop-writes-on-bgsave-error yes
rdbcompression yes
dbfilename dump.rdb
dir ./
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 16mb
aof-load-truncated yes

3.1演练重启redis,键值是否丢失

1
2
3
4
5
6
7
8
9
10
192.168.163.156:6379> set blog "blog.51cto.com"
OK
192.168.163.156:6379> exit
[root@hadoop2 redis]# pkill redis
#重启
[root@hadoop2 redis]# bin/redis-server  redis.conf 
[root@hadoop2 redis]# bin/redis-cli  -h  192.168.163.156
#键值未丢失
192.168.163.156:6379> get blog
"blog.51cto.com"

结论:托AOF的福,键值没有丢失,和RDB不同。原因是两者的触发时机不同。

这时候,确认下生产AOF文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#仅仅存了一条记录
[root@hadoop2 redis]# ll
-rw-r--r--. 1 root root    67 9月   3 10:31 appendonly.aof
#查看日志内容(为文本文件)
[root@hadoop2 redis]# cat appendonly.aof 
*2
$6
SELECT
$1
0
*3
$3
set
$4
blog
$14
blog.51cto.com

3.2演练重启AOF重写效果

通过查看日志内容,可以确认存放的是操作命令日志。这势必导致文件大小增长过快,这和RDB文件不同。RDB存储的是二进制文件,而且是某时刻的快照,存储的本身就是面向内存结果。稍后会提供例子演示下RDB的内容。

准备测试数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
[root@hadoop2 redis]# bin/redis-cli  -h  192.168.163.156
#顺序操作键值多次
192.168.163.156:6379> set year 2001
OK
192.168.163.156:6379> incr year
(integer) 2002
192.168.163.156:6379> incr year
(integer) 2003
192.168.163.156:6379> incr year
(integer) 2004
192.168.163.156:6379> incr year
(integer) 2005
192.168.163.156:6379> incr year
(integer) 2006
192.168.163.156:6379> incr year
(integer) 2007
192.168.163.156:6379> incr year
(integer) 2008
192.168.163.156:6379> incr year
(integer) 2009
192.168.163.156:6379> incr year
(integer) 2010
192.168.163.156:6379> get year
"2010"
# get没有输出到AOF日志
[root@hadoop2 redis]# cat appendonly.aof 
*2
$6
SELECT
$1
0
*3
$3
set
$4
blog
$14
blog.51cto.com
*2
$6
SELECT
$1
0
*3
$3
set
$4
year
$4
2001
*2
$4
incr
$4
year
*2
$4
incr
$4
year
*2
$4
incr
$4
year
*2
$4
incr
$4
year
*2
$4
incr
$4
year
*2
$4
incr
$4
year
*2
$4
incr
$4
year
*2
$4
incr
$4
year
*2
$4
incr
$4
year
#接下来,借助benchmark工具,批量插入数据,触发AOF文件重写
[root@hadoop2 redis]# bin/redis-benchmark  -r 20000 -h 192.168.163.156
#appendonly.aof文件变化过程(11M->27M -->32M->33M->42M->8.5M.
...
[root@hadoop2 redis]# ll appendonly.aof  -h
-rw-r--r--. 1 root root 11M 9月   3 11:03 appendonly.aof
-rw-r--r--. 1 root root 27M 9月   3 11:03 appendonly.aof
[root@hadoop2 redis]# ll appendonly.aof  -h
-rw-r--r--. 1 root root 32M 9月   3 11:04 appendonly.aof
[root@hadoop2 redis]# ll appendonly.aof  -h
-rw-r--r--. 1 root root 33M 9月   3 11:04 appendonly.aof
[root@hadoop2 redis]# ll appendonly.aof  -h
-rw-r--r--. 1 root root 36M 9月   3 11:04 appendonly.aof
[root@hadoop2 redis]# ll appendonly.aof  -h
-rw-r--r--. 1 root root 42M 9月   3 11:04 appendonly.aof
[root@hadoop2 redis]# ll appendonly.aof  -h
-rw-r--r--. 1 root root 44M 9月   3 11:04 appendonly.aof
[root@hadoop2 redis]# ll appendonly.aof  -h
-rw-r--r--. 1 root root 8.5M 9月   3 11:04 appendonly.aof
[root@hadoop2 redis]# ll appendonly.aof  -h
-rw-r--r--. 1 root root 11M 9月   3 11:04 appendonly.aof
[root@hadoop2 redis]# ll appendonly.aof  -h
-rw-r--r--. 1 root root 15M 9月   3 11:04 appendonly.aof

从42M 突然变成了8.5M,明显发生了AOF重写操作。

以year为目标,确认下AOF重写发生了什么。

重写前后,发现将多次操作的结果,转换为一个等价的命令,大大降低了存储空间。

1.我们也可以使用bgrewriteaof来手动触发AOF的自动重写。

2 .调用 BGSAVE 能手动触发快照保存,保存快照。

但线上环境要注意,阻塞情况。

4.AOF VS RDB.

两种持久化方式,不是水火不容,而是相互扶持,相融以沫。

官方文档,建议两者同时开启

同时开启两种持久化(redis.conf)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
dbfilename dump.rdb
dir ./
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 16mb
aof-load-truncated yes

4.1比较2种方式的文件存储

1
2
3
4
5
6
7
8
9
10
1.删除rdb,aof文件
2.重启redis-server
#3.批量发送1w条请求
[root@hadoop2 redis]# bin/redis-benchmark  -r 10000 -h 192.168.163.156
#4. 比较2个文件大小
[root@hadoop2 redis]# ll -h
总用量 29M
-rw-r--r--. 1 root root  192 9月   3 10:58 1
-rw-r--r--. 1 root root  28M 9月   3 11:26 appendonly.aof
-rw-r--r--. 1 root root 457K 9月   3 11:26 dump.rdb

4.2 演练aof文件损坏

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@hadoop2 redis]# bin/redis-server  redis.conf 
[root@hadoop2 redis]# bin/redis-cli  -h 192.168.163.156
192.168.163.156:6379> set blog "blog.51cto.com"
OK
192.168.163.156:6379> set subject "redis"
OK
192.168.163.156:6379> set year 2016
OK
192.168.163.156:6379> keys *
1) "year"
2) "subject"
3) "blog"

手动修改下appendonly.aof 文件

使用redis-check-aof 验证下,果然不出所料“文件有问题”

1
2
3
4
5
6
[root@hadoop2 redis]# bin/redis-check-aof 
Usage: bin/redis-check-aof [--fix] <file.aof>
[root@hadoop2 redis]# bin/redis-check-aof  appendonly.aof 
0x               0: Expected \r\n, got: 0a00
AOF analyzed: size=112, ok_up_to=0, diff=112
AOF is not valid

...查看启动日志(WARRING 暂时先放着)

1
2
3
4
4690:M 03 Sep 11:42:12.213 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
4690:M 03 Sep 11:42:12.213 # Server started, Redis version 3.2.3
4690:M 03 Sep 11:42:12.213 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
4690:M 03 Sep 11:42:12.214 # Bad file format reading the append only file: make a backup of your AOF file, then use ./redis-check-aof --fix <filename>

客户端连接失败

[root@hadoop2 redis]# bin/redis-cli  -h 192.168.163.156
Could not connect to Redis at 192.168.163.156:6379: Connection refused

修复aof文件

[root@hadoop2 redis]# bin/redis-check-aof 
Usage: bin/redis-check-aof [--fix] <file.aof>
[root@hadoop2 redis]# bin/redis-check-aof --fix appendonly.aof 
0x               0: Expected \r\n, got: 0a00
AOF analyzed: size=112, ok_up_to=0, diff=112
This will shrink the AOF from 112 bytes, with 112 bytes, to 0 bytes
Continue? [y/N]: y

Successfully truncated AOF

#修复的结果是清空了AOF文件。

重启成功了,但遗憾的是数据全丢失了。

bin/redis-server  redis.conf

[root@hadoop2 redis]# cat appendonly.aof

bin/redis-cli  -h  192.168.163.156
192.168.163.156:6379> keys *
(empty list or set)

当然,演示AOF文件出问题,这是个比较严重的问题。可见备份的重要性。

AOF方式的另一个好处,我们通过一个“场景再现”来说明。某同学在操作redis时,不小心执行了FLUSHALL,导致redis内存中的数据全部被清空了,这是很悲剧的事情。不过这也不是世界末日,只要redis配置了AOF持久化方式,且AOF文件还没有被重写(rewrite),我们就可以用最快的速度暂停redis并编辑AOF文件,将最后一行的FLUSHALL命令删除,然后重启redis,就可以恢复redis的所有数据到FLUSHALL之前的状态了。是不是很神奇,这就是AOF持久化方式的好处之一。但是如果AOF文件已经被重写了,那就无法通过这种方法来恢复数据了。

前人,曾静曰过的。难道有问题。于是我重新实验了下。

这次我加快了速度,立刻关闭redis服务,以及使用vi命令直接修改aof文件。结果却是可以将数据恢复。

这个演示不补贴了。

本文转自 randy_shandong 51CTO博客,原文链接:http://blog.51cto.com/dba10g/1845885,如需转载请自行联系原作者

redis演练(5) redis持久化相关推荐

  1. redis演练(7) redis Sentinel实现故障转移

    书接上文<redis演练(6) redis主从模式搭建>. <redis演练(6) redis主从模式搭建>中仅仅配置了redis主从环境.分别配置了2个主从结构. 分别是1. ...

  2. redis演练(3) redis事务管理

    redis与memcached对比,redis不仅适合做缓存,而且可以做存储,这就有点数据库的影子了.说到数据库,事务是一个很重要的一个方面. 数据库事务 (简称:事务)是数据库管理系统执行过程中的一 ...

  3. redis 数据结构 内存管理 持久化

    为什么80%的码农都做不了架构师?>>>    Redis 内存数据结构与编码 OBJECT encoding key.DEBUG OBJECT key 简单动态字符串(simple ...

  4. Redis的两种持久化机制RDB和AOF

    目录 RDB 原理 触发时机 AOF 原理 开启AOF aof日志文件说明 触发时机 aof的重写机制 redis4.0的混合持久化机制 总结 rdb持久化文件的名称:dump.rdb.存储在配置文件 ...

  5. 07_NoSQL数据库之Redis数据库:Redis的高级应用之事务处理、持久化操作、pub_sub、虚拟内存

     事务处理 Redis对事务的支持目前还比较简单.Redis只能保证一个client发起的事务中的命令可以连续的执行,而中间不会插入其他client的命令.当一个client在一个连接中发出mul ...

  6. redis 硬件要求_Redis持久化机制

    介绍 Redis所有的数据都保存在内存中,数据的更新将异步的保存到硬盘上,当需要恢复数据时,从硬盘上将数据再读取到内存中,这就是Redis的持久化过程.主流的持久化方式有两种: 快照:MySQL的Du ...

  7. Redis数据库(二)——Redis高可用、持久化及性能管理

    Redis数据库(二)--Redis高可用.持久化及性能管理 一.Redis 高可用 主要的高可用技术 二.Redis 持久化 1.持久化的功能 2.两种持久化方式 3.RDB 和 AOF 的区别 ① ...

  8. redis专题:redis的持久化方式有哪些?redis数据的备份和恢复策略

    文章目录 1. 为什么要做redis持久化? 2. 持久化方式之---RDB快照(snapshot) 3. 持久化方式之---AOF(append-only file) 4. 持久化方式之---混合持 ...

  9. Redis内存回收和持久化策略

    概述 Redis所有数据都存在内存中,在某些时候需要对占用的内存空间进行回收,内存回收主要分为两类,一类是key过期,一类是内存使用达到上限,触发内存淘汰. Key过期策略 要实现key过期,有几种思 ...

最新文章

  1. 机器学习笔记:牛顿方法
  2. 北京航空航天大学计算机专业培养方案,北京航空航天大学计算机科学与技术专业...
  3. SAP Commerce Accelerator和SAP Spartacus的技术对比
  4. 除了 Python ,这些语言写的机器学习项目也很牛
  5. 华为怎么升级Android11,华为EMUI 11/安卓11升级名单曝光 快来看看你的手机是否支持...
  6. C#中如何将字符串转换byte[],同时如何将byte[]换成字符串?
  7. mysql 正则regrx_正则表达式
  8. Spring Cloud Greenwich 新特性和F升级分享
  9. C程序设计语言现代方法18:声明
  10. navicat黑色_“黑色星期五”之SQL浅析
  11. GridView中使用DropDownList的OnSelectedIndexChanged事件
  12. 职工信息管理系统C++代码
  13. F28335第一篇——看门狗的开断
  14. nbu备份社区版mysql_mysql数据备份之NBU
  15. Java主流框架的介绍
  16. Unity TextMeshPro 制作字体用简体中文字符集 (仅用于开发)
  17. 红色警戒2修改器原理百科(二)
  18. Python绘制三维立体图详解与绘图填充
  19. 小蓝本 第一本 《因式分解技巧》 第七章 综合运用 笔记 (第七天)
  20. 关于typedef的用法总结

热门文章

  1. TraceRoute原理
  2. java mysql 分布式锁_Java分布式锁之数据库方式实现
  3. Nginx动态路由的新姿势:使用Go取代lua
  4. 解决在ueditor中上传图片通过后台java+SpringMVC添加水印方法
  5. 【pwnable】asm之write up
  6. 使用 pipe 在程序正文中捕获和处理信号
  7. Windows Nano Server安装配置详解07:部署IIS
  8. Android studio 查看sha1
  9. IE打印控件推荐-4fang pazu
  10. Report_客制化Excel报表中的XLS标记(案例)