千家信息网

Redis笔记整理(三):进阶操作与高级部分

发表于:2025-01-21 作者:千家信息网编辑
千家信息网最后更新 2025年01月21日,[TOC]Redis发布订阅Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。Redis客户端可以订阅任意数量的频道。下图展示了频道chann
千家信息网最后更新 2025年01月21日Redis笔记整理(三):进阶操作与高级部分

[TOC]


Redis发布订阅

Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。Redis客户端可以订阅任意数量的频道。下图展示了频道channel1,以及订阅这个频道的三个客户端--client1,client2,client5之间的关系。当有新消息通过PUBLISH命令发送给频道channel1时,这个消息就会被发送给订阅它的三个客户端:

相关操作命令如下:

命令描述
PSUBSCRIBE pattern [pattern ...]订阅一个或多个符合给定模式的频道
PUSBSUB subcommand [argument [argument...]]查看订阅与发布系统状态
PUBLISH channel message将消息发送到指定的频道
PUNSUBSCRIBE [ pattern [pattern ...]]退订所有给定模式的频道
SUBSCRIBE channel [channel ...]订阅给定的一个或多个频道的信息
UNSUBSCRIBE [channel [channel ...]]指退订给定的频道

举例如下:

创建的订阅频道名为redisChatlocalhost:6379> SUBSCRIBE redisChat1) "subscribe"2) "redisChat   重新打开一个新的redis客户端,然后在同一个频道redisChat发布两次消息,订阅者就能接收到相关消息。127.0.0.1:6379> PUBLISH redisChat "jack is handsome boy"这时在订阅端中很快就可以看到该消息。

Redis事务

  Redis事务可以一次执行多个命令,并且带有以下两个重要的保证:   事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。                          事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。   事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。   一个事务从开始到执行会经历三个阶段:      开始事务。      命令入队。      执行事务。

其相关操作命令如下:

命令描述
DISCARD取消事务,放弃执行事务块内的所有命令
EXEC执行所有事务块内的命令
MULTI标记一个事务块的开始
UNWATCH取消WATCH命令对所有key的监视
WATCH key [key ...]监视一个或多个key,如果在事务执行之前这些key被其它命令所改动,那么事务将被打断

举例如下:

uplooking01:7001> get name"xpleaf"uplooking01:7001> MULTIOKuplooking01:7001> get nameQUEUEDuplooking01:7001> set name yyhQUEUEDuplooking01:7001> get nameQUEUEDuplooking01:7001> EXEC1) "xpleaf"2) OK3) "yyh"

Redis命令总结

Redis的常用命令主要分为两个方面、一个是键值相关命令、一个是服务器相关命令1、键值相关命令      keys * 取出当前所有的key      exists name 查看redis是否有name这个key      del name 删除key name      expire confirm 100 设置confirm这个key100秒过期      ttl confirm 获取confirm 这个key的有效时长      select 0 选择到0数据库 redis默认的数据库是0~15一共16个数据库      move confirm 1 将当前数据库中的key移动到其他的数据库中,      persist confirm 移除confirm这个key的过期时间      randomkey 随机返回数据库里面的一个key      rename key2 key3 重命名key2 为key3      type key2 返回key的数据类型2、服务器相关命令      ping PONG返回响应是否连接成功      echo 在命令行打印一些内容      select 0~15 编号的数据库      quit  /exit 退出客户端      dbsize 返回当前数据库中所有key的数量      info 返回redis的相关信息      config get dir/* 实时传储收到的请求      flushdb 删除当前选择数据库中的所有key      flushall 删除所有数据库中的数据库

Redis安全

我们可以通过redis的配置文件设置密码参数,这样客户端连接到redis服务就需要密码验证,这样可以让你的redis服务更安全。

我们可以通过以下命令查看是否设置了密码验证:

uplooking01:7001> config get requirepass1) "requirepass"2) ""

默认情况下requirepass参数是空的,这就意味着无需密码验证就可以连接到redis服务。如果设置密码,客户端连接redis服务就需要密码验证。否则无法执行命令,有两方式完成认证:

可以在连接时就指定密码:redis-cli -h uplooking03 -a uplooking也可以先连接,到终端后再认证:auth uplooking

Redis管道与性能测试

   Redis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务。这意味着通常情况下一个请求会遵循以下步骤:   客户端向服务端发送一个查询请求,并监听scoket返回,通常是以阻塞模式,等待服务端响应。   服务端处理命令,并将结果返回给客户端。   Redis管道技术可以在服务端末响应时,客户端可以继续想服务端发送请求,并最终一次性读取所有服务端的相应。

下面使用Java代码来进行测试:

package com.uplooking.bigdata;import com.uplooking.bigdata.common.util.redis.JedisUtil;import org.junit.Test;import redis.clients.jedis.Jedis;import redis.clients.jedis.Pipeline;/** * 使用管道和不使用管道的性能测试对比 */public class PipelineTest {    @Test    public void testPipeline() {        int count = 10000;        // 标记不使用管道操作时的开始时间        long start = System.currentTimeMillis();        // 不使用管道执行操作        withoutPipeline(count);        // 标记不使用管道操作时的结束时间        long end = System.currentTimeMillis();        // 输出不使用管道进行操作时所消耗的时间        System.out.println("withoutPipeline: " + (end-start));        // 标记使用管道操作时的开始时间        start = System.currentTimeMillis();        // 使用管道执行操作        usePipeline(count);        // 标记使用管道操作时的结束时间        end = System.currentTimeMillis();        // 输出使用管道进行操作时所消耗的时间        System.out.println("usePipeline: " + (end-start));    }    private void withoutPipeline(int count) {        JedisUtil.getJedis();        Jedis jedis = JedisUtil.getJedis();        for(int i =0; i < count; i++) {            jedis.incr("testKey1");        }        cleanUp(jedis);    }    private void usePipeline(int count) {        Jedis jedis = JedisUtil.getJedis();        Pipeline pl = jedis.pipelined();        for(int i =0; i < count; i++) {            pl.incr("testKey1");        }        pl.sync();        cleanUp(jedis);    }    public void cleanUp(Jedis jedis) {        JedisUtil.returnJedis(jedis);    }}

JedisUtil可以查看前面的代码,这里就不再给出。

输出结果如下:

withoutPipeline: 1935usePipeline: 60

测试结果还是有明显的差距,所以多次操作使用pipeline还是有明显的优势。

Redis性能测试:读写能力查看

 Redis性能测试是通过同时执行多个命令实现的。语法  redis-benchmark [option] [option-value]实例  以下实例同时执行10000个请求来检测性能:  1)、redis-benchmark -n 100000  2)、redis-benchmark -h localhost -p 6379 -t set,lpush -n 100000 -q

其常见的命令选项如下:

选项描述默认值
-h指定服务器主机名127.0.0.1
-p指定服务器端口6379
-s指定服务器socket
-c指定并发连接数50
-n指定请求数10000
-d以字节的形式指定set/get值的数据大小2
-k1=keep alive 0=reconnect1
-rset/get/incr使用随机key,sadd使用随机值
-P通过管道传输请求1
-q强制退出redis。仅显示query/sec值
-csv以CSV格式输出
-l生产循环,永久执行测试
-t仅运行以逗号分割的测试命令列表
-IIdle模式。仅打开N个idle连接并等待

完整测试案例

[uplooking@uplooking01 ~]$ redis-benchmark -h uplooking01 -p 6379 -n 100000 -c 20====== PING_INLINE ======  100000 requests completed in 1.29 seconds  20 parallel clients  3 bytes payload  keep alive: 199.96% <= 1 milliseconds100.00% <= 1 milliseconds77459.34 requests per second====== PING_BULK ======  100000 requests completed in 1.33 seconds  20 parallel clients  3 bytes payload  keep alive: 199.95% <= 1 milliseconds99.96% <= 2 milliseconds100.00% <= 2 milliseconds75187.97 requests per second====== SET ======  100000 requests completed in 1.29 seconds  20 parallel clients  3 bytes payload  keep alive: 199.96% <= 1 milliseconds99.98% <= 2 milliseconds99.98% <= 4 milliseconds99.99% <= 5 milliseconds100.00% <= 5 milliseconds77339.52 requests per second====== GET ======  100000 requests completed in 1.35 seconds  20 parallel clients  3 bytes payload  keep alive: 199.98% <= 1 milliseconds100.00% <= 1 milliseconds74239.05 requests per second====== INCR ======  100000 requests completed in 1.29 seconds  20 parallel clients  3 bytes payload  keep alive: 199.98% <= 1 milliseconds100.00% <= 1 milliseconds77279.75 requests per second====== LPUSH ======  100000 requests completed in 1.28 seconds  20 parallel clients  3 bytes payload  keep alive: 199.98% <= 1 milliseconds100.00% <= 1 milliseconds77821.02 requests per second====== RPUSH ======  100000 requests completed in 1.28 seconds  20 parallel clients  3 bytes payload  keep alive: 199.94% <= 1 milliseconds100.00% <= 1 milliseconds77881.62 requests per second====== LPOP ======  100000 requests completed in 1.27 seconds  20 parallel clients  3 bytes payload  keep alive: 199.99% <= 1 milliseconds100.00% <= 1 milliseconds78616.35 requests per second====== RPOP ======  100000 requests completed in 1.27 seconds  20 parallel clients  3 bytes payload  keep alive: 199.92% <= 1 milliseconds100.00% <= 1 milliseconds78678.20 requests per second====== SADD ======  100000 requests completed in 1.34 seconds  20 parallel clients  3 bytes payload  keep alive: 199.99% <= 1 milliseconds100.00% <= 1 milliseconds74404.77 requests per second====== SPOP ======  100000 requests completed in 1.34 seconds  20 parallel clients  3 bytes payload  keep alive: 199.96% <= 1 milliseconds100.00% <= 1 milliseconds74738.41 requests per second====== LPUSH (needed to benchmark LRANGE) ======  100000 requests completed in 1.27 seconds  20 parallel clients  3 bytes payload  keep alive: 199.96% <= 1 milliseconds100.00% <= 1 milliseconds78492.93 requests per second====== LRANGE_100 (first 100 elements) ======  100000 requests completed in 2.81 seconds  20 parallel clients  3 bytes payload  keep alive: 199.87% <= 1 milliseconds99.98% <= 2 milliseconds100.00% <= 3 milliseconds35536.61 requests per second====== LRANGE_300 (first 300 elements) ======  100000 requests completed in 7.59 seconds  20 parallel clients  3 bytes payload  keep alive: 197.91% <= 1 milliseconds99.83% <= 2 milliseconds99.96% <= 3 milliseconds100.00% <= 4 milliseconds100.00% <= 4 milliseconds13166.56 requests per second====== LRANGE_500 (first 450 elements) ======  100000 requests completed in 10.27 seconds  20 parallel clients  3 bytes payload  keep alive: 137.79% <= 1 milliseconds99.54% <= 2 milliseconds99.91% <= 3 milliseconds99.97% <= 4 milliseconds99.99% <= 5 milliseconds100.00% <= 6 milliseconds100.00% <= 6 milliseconds9734.25 requests per second====== LRANGE_600 (first 600 elements) ======  100000 requests completed in 13.01 seconds  20 parallel clients  3 bytes payload  keep alive: 10.72% <= 1 milliseconds98.59% <= 2 milliseconds99.76% <= 3 milliseconds99.94% <= 4 milliseconds99.98% <= 5 milliseconds100.00% <= 6 milliseconds7689.35 requests per second====== MSET (10 keys) ======  100000 requests completed in 1.69 seconds  20 parallel clients  3 bytes payload  keep alive: 199.98% <= 1 milliseconds100.00% <= 1 milliseconds59241.71 requests per second

可以看到执行了多个命令进行测试,如果只是希望测试部分命令的性能情况,可以参考下面的部分测试案例。

部分测试案例

[uplooking@uplooking01 ~]$ redis-benchmark -h uplooking01 -p 6379 -t set,lpush -n 100000 -qSET: 75301.21 requests per secondLPUSH: 77101.00 requests per second

通过上面的测试,我们就可以知道我们的Redis环境的读写能力究竟如何。

Redis数据持久化

RDB(默认)

rdb方式的持久化是通过快照完成的,当符合一定条件时redis会自动将内存中的所有数据执行快照操作并存储到硬盘上。默认存储在dump.rdb文件中。(文件名在配置文件中dbfilename)redis进行快照的时机(在配置文件redis.conf中)save 900 1:表示900秒内至少一个键被更改则进行快照。save 300 10save 60 10000(redis自动实现快照的过程,见下面的文档内容)手动执行save或者bgsave命令让redis执行快照。两个命令的区别在于,save是由主进程进行快照操作,会阻塞其它请求。bgsave是由redis执行fork函数复制出一个子进程来进行快照操作。文件修复:redis-check-dumprdb的优缺点优点:由于存储的有数据快照文件,恢复数据很方便。缺点:会丢失最后一次快照以后更改的所有数据。

redis实现快照的过程:

1:redis使用fork函数复制一份当前进程的副本(子进程)2:父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件3:当子进程写入完所有数据后会用该临时文件替换旧的RDB文件,至此,一次快照操作完成。注意:redis在进行快照的过程中不会修改RDB文件,只有快照结束后才会将旧的文件替换成新的,也就是说任何时候RDB文件都是完整的。这就使得我们可以通过定时备份RDB文件来实现redis数据库的备份RDB文件是经过压缩的二进制文件,占用的空间会小于内存中的数据,更加利于传输。

AOF

AOF基本配置
aof方式的持久化是通过日志文件的方式。默认情况下redis没有开启aof,可以通过参数appendonly参数开启。    appendonly yesaof文件的保存位置和rdb文件的位置相同,都是dir参数设置的,默认的文件名是appendonly.aof,可以通过         appendfilename参数修改    appendfilename appendonly.aof

redis写命令同步的时机:

#appendfsync always 每次都会执行appendfsync everysec 默认 每秒执行一次同步操作(推荐,默认)#appendfsync no不主动进行同步,由操作系统来做,30秒一次

另外查看aof日志文件,它的内容如下:

[uplooking@uplooking01 redis]$ tail -f appendonly.aofsingle$2no*3$3SET$3age$218

其相关符号的说明如下:

*<参数数量>$<参数 1 的字节数量> <参数 1 的数据> ...$<参数 N 的字节数量> <参数 N 的数据> 
aof日志文件重写
  auto-aof-rewrite-percentage 100(当目前aof文件大小超过上一次重写时的aof文件大小的百分之多少时会再次进行重写,如果之前没有重写,则以启动时的aof文件大小为依据)  auto-aof-rewrite-min-size 64mb  手动执行bgrewriteaof进行重写  重写的过程只和内存中的数据有关,和之前的aof文件无关。  所谓的"重写"其实是一个有歧义的词语, 实际上,   AOF 重写并不需要对原有的 AOF 文件进行任何写入和读取, 它针对的是数据库中键的当前值。文件修复:redis-check-aof

对于aof日志文件重写的概念再进一步说明:

所谓"重写"其实是一个有歧义的词语,实际上,AOF重写并不需要对原有AOF文件进行任何写入和读取,它针对的是数据库中键的当前值。假设服务器对键list执行了以下四条命令:127.0.0.1:6379[1]> RPUSH list 1 2 3 4    //[1,2,3,4]127.0.0.1:6379[1]> RPOP list                    //[1,2,3]127.0.0.1:6379[1]> LPOP list            //[2,3]当前列表键list在数据库中的值就为[2,3]。要保存这个列表的当前状态,并且尽量减少使用的命令数,最简单的方式不是去AOF文件分析前面执行的三条命令,而是直接读取list键在数据库中的当前值,然后用一条RPUSH 2,3代替前面的三条命令。根据键的类型,使用适当的写入命令来重现键的当前值,这就是AOF重写的实现原理
rdb切换到aof
动态切换redis持久方式,从RDB切换到AOF(支持Redis 2.2及以上)  CONFIG SET appendonly yes  CONFIG SET save ""(可选)注意:当redis启动时,如果rdb持久化和aof持久化都打开了,那么程序会使用aof方式来恢复数据集,因为aof方式所保存的数据通常是最完整的。如果aof文件丢失了,则启动之后数据库内容为空。注意:如果想把正在运行的redis数据库,从RDB切换到AOF,建议先使用动态切换方式,再修改配置文件,重启数据库。(不能自己修改配置文件,重启数据库,否则数据库中数据就为空了。因为此时会直接读取aof文件的数据,rdb的数据文件还存在,但是redis只会加载aof日志文件。)

在实际测试时,效果跟上面的描述是一样的:

1.先使用rdb的方式作为数据的持久化方式2.向redis中添加数据3.动态执行CONFIG SET appendonly yes然后会发现在redis目录下动态生成一个aof文件,并且其数据就是当前redis内存中的数据。并且通过测试发现,假如age这个key是原来rdb中存在的数据,一旦动态切换,原来rdb的数据都会备份到aof日志文件中,这样也就验证了,其实动态切换的过程,会把当前redis内存中的数据都保存到aof日志文件中。

Redis优化

Redis内存占用情况

 100万个键值对(键是0到999999值是字符串"hello world")在32位操作系统的笔记本上用了100MB使用64位的操作系统的话,相对来说占用的内存会多一点,这是因为64位的系统里指针占用了8个字节,但是64位系统也能支持更大的内存,所以运行大型的redis服务还是建议使用64位服务器一个Redis实例最多能存放多少keys   理论上Redis可以处理多达232-1的keys,并且在实际中进行了测试,每个实例至少存放了2亿5千万的keys   也可以说Redis的存储极限是系统中的可用内存值。

Redis优化1:基本优化

1.精简键名和键值  键名:尽量精简,但是也不能单纯为了节约空间而使用不易理解的键名。  键值:对于键值的数量固定的话可以使用0和1这样的数字来表示,(例如:male/female、right/wrong)2.当业务场景不需要数据持久化时,关闭所有的持久化方式可以获得最佳的性能3.内部编码优化(了解)    redis为每种数据类型都提供了两种内部编码方式,在不同的情况下redis会自动调整合适的编码方式。(如图所示)4.SLOWLOG [get/reset/len]  slowlog-log-slower-than 它决定要对执行时间大于多少微秒(microsecond,1秒 = 1,000,000 微秒)的命令进行记录  slowlog-max-len 它决定 slowlog 最多能保存多少条日志  当发现redis性能下降的时候可以查看下是哪些命令导致的

Redis优化2:内存使用优化

1.限制redis的内存大小  通过redis的info命令查看内存使用情况  如果不设置maxmemory或者设置为0,64位系统不限制内存,32位系统最多使用3GB内存。  修改配置文件中的maxmemory和maxmemory-policy  maxmemory:最大内存  maxmemory-policy:内存不足时,数据清除策略1.如果可以确定数据总量不大,并且内存足够的情况下不需要限制redis使用的内存大小。  如果数据量不可预估,并且内存也有限的话,尽量限制下redis使用的内存大小,这样可以避免redis使用swap分区。注意:如果不限制内存,当物理内存使用完之后,会使用swap分区,这样性能较低,如果限制了内存,     当到达指定内存之后就不能添加数据了,否则会报OOM错误。     可以设置maxmemory-policy,内存不足时删除数据。

更详细的说明如下:

在硬盘上进行读写操作要比在内存上进行读写操作,时间上慢了近5个数量级,内存是0.1μs(微秒)、而硬盘是10ms(毫秒)。如果Redis进程上发生内存交换,那么Redis和依赖Redis上数据的应用会受到严重的性能影响。 通过查看used_memory指标可知道Redis正在使用的内存情况,如果used_memory>可用最大内存,那就说明Redis实例正在进行内存交换或者已经内存交换完毕。管理员根据这个情况,执行相对应的应急措施。

排查方案:若是在使用Redis期间没有开启rdb快照或aof持久化策略,那么缓存数据在Redis崩溃时就有丢失的危险。因为当Redis内存使用率超过可用内存的95%时,部分数据开始在内存与swap空间来回交换,这时就可能有丢失数据的危险。当开启并触发快照功能时,Redis会fork一个子进程把当前内存中的数据完全复制一份写入到硬盘上。因此若是当前使用内存超过可用内存的45%时触发快照功能,那么此时进行的内存交换会变的非常危险(可能会丢失数据)。 倘若在这个时候实例上有大量频繁的更新操作,问题会变得更加严重。

通过减少Redis的内存占用率,来避免这样的问题,或者使用下面的技巧来避免内存交换发生:1:尽可能的使用Hash数据结构。因为Redis在储存小于100个字段的Hash结构上,其存储效率是非常高的。所以在不需要集合(set)操作或list的push/pop操作的时候,尽可能的使用Hash结构。比如,在一个web应用程序中,需要存储一个对象表示用户信息,使用单个key表示一个用户,其每个属性存储在Hash的字段里,这样要比给每个属性单独设置一个key-value要高效的多。 通常情况下倘若有数据使用string结构,用多个key存储时,那么应该转换成单key多字段的Hash结构。 如上述例子中介绍的Hash结构应包含,单个对象的属性或者单个用户各种各样的资料。Hash结构的操作命令是HSET(key, fields, value)和HGET(key, field),使用它可以存储或从Hash中取出指定的字段。

2:设置key的过期时间。一个减少内存使用率的简单方法就是,每当存储对象时确保设置key的过期时间。倘若key在明确的时间周期内使用或者旧key不大可能被使用时,就可以用Redis过期时间命令(expire,expireat, pexpire, pexpireat)去设置过期时间,这样Redis会在key过期时自动删除key。 假如你知道每秒钟有多少个新key-value被创建,那可以调整key的存活时间,并指定阀值去限制Redis使用的最大内存。

3:回收key。在Redis配置文件中(一般叫Redis.conf),通过设置"maxmemory"属性的值可以限制Redis最大使用的内存,修改后重启实例生效。也可以使用客户端命令config set maxmemory 去修改值,这个命令是立即生效的,但会在重启后会失效,需要使用config rewrite命令去刷新配置文件。 若是启用了Redis快照功能,应该设置"maxmemory"值为系统可使用内存的45%,因为快照时需要一倍的内存来复制整个数据集,也就是说如果当前已使用45%,在快照期间会变成95%(45%+45%+5%),其中5%是预留给其他的开销。 如果没开启快照功能,maxmemory最高能设置为系统可用内存的95%。

当内存使用达到设置的最大阀值时,需要选择一种key的回收策略,可在Redis.conf配置文件中修改"maxmemory-policy"属性值。 若是Redis数据集中的key都设置了过期时间,那么"volatile-ttl"策略是比较好的选择。但如果key在达到最大内存限制时没能够迅速过期,或者根本没有设置过期时间。那么设置为"allkeys-lru"值比较合适,它允许Redis从整个数据集中挑选最近最少使用的key进行删除(LRU淘汰算法)。Redis还提供了一些其他淘汰策略,如下:volatile-lru:使用LRU算法从已设置过期时间的数据集合中淘汰数据。volatile-ttl:从已设置过期时间的数据集合中挑选即将过期的数据淘汰。volatile-random:从已设置过期时间的数据集合中随机挑选数据淘汰。allkeys-lru:使用LRU算法从所有数据集合中淘汰数据。allkeys-random:从数据集合中任意选择数据淘汰no-enviction:禁止淘汰数据。

通过设置maxmemory为系统可用内存的45%或95%(取决于持久化策略)和设置"maxmemory-policy"为"volatile-ttl"或"allkeys-lru"(取决于过期设置),可以比较准确的限制Redis最大内存使用率,在绝大多数场景下使用这2种方式可确保Redis不会进行内存交换。倘若你担心由于限制了内存使用率导致丢失数据的话,可以设置noneviction值禁止淘汰数据。

Redis优化3

Redis是个单线程模型,客户端过来的命令是按照顺序执行的,所以想要一次添加多条数据的时候可以使用管道(可以理解为批处理),或者使用一次可以添加多条数据的命令,例如:

setmset
getmget
lindexlrange
hsethmset
hgethmget
数据 内存 命令 文件 快照 数据库 时间 服务 测试 事务 客户 客户端 方式 管道 系统 订阅 情况 频道 限制 性能 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 思科网络技术论文6 网络安全法强化了 数据库 2003版本 宝鸡市政府网络安全知识 网络安全风险评估报告内容 热血传奇手游推荐哪个服务器 邢台市桥西区网络安全 手机云数据库可以删吗 骑手配送软件开发 未转变者联机开服务器教程 曹妃甸区专业性软件开发常见问题 电脑上的网络安全密匙是什么 科学小实验网络技术服务 战地5可以选择服务器吗 软件开发四性检查 世界网络安全大赛个人排名 网络安全行业法律法规标准 青海智慧团建软件开发电话 静态页面部署到服务器 广西统筹建设网络安全态势感知 adm软件开发是什么意思 学校网络安全信息科设置 nbu备份服务器丢包 智能医疗系统软件开发哪家专业 网鼎杯网络安全大赛比赛题目 湖北超频服务器服务至上 数据库的四个主要特点是什么 将数据库拷贝到另一台机器上 基岩版服务器如何安装插件 单位网络安全处罚
0