Python面试题解析之数据库与缓存

python面试题解析(数据库和缓存)

 
  1. 答:

关系型数据库:Mysql,Oracel,Microsoft SQL Serverpython

非关系型数据库:MongoDB,memcache,Redis。mysql

 

  1. 答:

     MyISAM:在Web、数据仓储和其余应用环境下最常使用的存储引擎之一。linux

  InnoDB:用于事务处理应用程序,具备众多特性,包括ACID事务支持(提供行级锁),Mysql在V5.1以前默认存储引擎是MyISAM;在此以后默认存储引擎是InnoDB面试

  BDB:可替代InnoDB的事务引擎,支持COMMIT、ROLLBACK和其余事务特性。redis

  Memory:将全部数据保存在RAM中,在须要快速查找引用和其余相似数据的环境下,可提供极快的访问。sql

  Merge:容许MySQL DBA或开发人员将一系列等同的MyISAM表以逻辑方式组合在一块儿,并做为1个对象引用它们。对于诸如数据仓储等VLDB环境十分适合。数据库

  Archive:为大量不多引用的历史、归档、或安全审计信息的存储和检索提供了完美的解决方案。编程

  Federated:可以将多个分离的MySQL服务器连接起来,从多个物理服务器建立一个逻辑数据库。十分适合于分布式环境或数据集市环境。windows

  Cluster/NDB:MySQL的簇式数据库引擎,尤为适合于具备高性能查找要求的应用程序,这类查找需求还要求具备最高的正常工做时间和可用性。缓存

Other:其余存储引擎包括CSV(引用由逗号隔开的用做数据库表的文件),Blackhole(用于临时禁止对数据库的应用程序输入),以及Example引擎(可为快速建立定制的插件式存储引擎提供帮助)。

 

  1. 答:

第一范式:确保每列的原子性.
    若是每列(或者每一个属性)都是不可再分的最小数据单元(也称为最小的原子单元),则知足第一范式.
    例如:顾客表(姓名、编号、地址、……)其中"地址"列还能够细分为国家、省、市、区等。

第二范式:在第一范式的基础上更进一层,目标是确保表中的每列都和主键相关.
    例如:订单表(订单编号、产品编号、定购日期、价格、……),"订单编号"为主键,"产品编号"和主键列没有直接的关系,即"产品编号"列不依赖于主键列,应删除该列。

第三范式:在第二范式的基础上更进一层,目标是确保每列都和主键列直接相关,而不是间接相关.
    为了理解第三范式,须要根据Armstrong千米之必定义传递依赖。假设A、B和C是关系R的三个属性,若是A-〉B且B-〉C,则从这些函数依赖中,能够得出A-〉C,如上所述,依赖A-〉C是传递依赖。
    例如:订单表(订单编号,定购日期,顾客编号,顾客姓名,……),初看该表没有问题,知足第二范式,每列都和主键列"订单编号"相关,再细看你会发现"顾客姓名"和"顾客编号"相关,"顾客编号"和"订单编号"又相关,最后通过传递依赖,"顾客姓名"也和"订单编号"相关。为了知足第三范式,应去掉"顾客姓名"列,放入客户表中。

4.答:

       通常来讲,事务是必须知足4个条件(ACID)::原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。

原子性:一个事务(transaction)中的全部操做,要么所有完成,要么所有不完成,不会结束在中间某个环节。事务在执行过程当中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务历来没有执行过同样。

一致性:在事务开始以前和事务结束之后,数据库的完整性没有被破坏。这表示写入的资料必须彻底符合全部的预设规则,这包含资料的精确度、串联性以及后续数据库能够自发性地完成预约的工做。

隔离性:数据库容许多个并发事务同时对其数据进行读写和修改的能力,隔离性能够防止多个事务并发执行时因为交叉执行而致使数据的不一致。事务隔离分为不一样级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。

持久性:事务处理结束后,对数据的修改就是永久的,即使系统故障也不会丢失。

 

MYSQL 事务处理主要有两种方法:

一、用 BEGIN, ROLLBACK, COMMIT来实现

BEGIN 开始一个事务

ROLLBACK 事务回滚

COMMIT 事务确认

二、直接用 SET 来改变 MySQL 的自动提交模式:

SET AUTOCOMMIT=0 禁止自动提交

SET AUTOCOMMIT=1 开启自动提交

 

5. 答:

做者模型:一个做者有姓名。

做者详细模型:把做者的详情放到详情表,包含性别,email地址和出生日期,做者详情模型和做者模型之间是一对一的关系(one-to-one)(相似于每一个人和他的身份证之间的关系),在大多数状况下咱们没有必要将他们拆分红两张表,这里只是引出一对一的概念。

出版商模型:出版商有名称,地址,所在城市,省,国家和网站。

书籍模型:书籍有书名和出版日期,一本书可能会有多个做者,一个做者也能够写多本书,因此做者和书籍的关系就是多对多的关联关系(many-to-many),一本书只应该由一个出版商出版,因此出版商和书籍是一对多关联关系(one-to-many),也被称做外键。

 

6. 答:

高并发之下使用内存数据库Redis,正常则使用表来进行计数。

DROP TABLE access_counter;

CREATE TABLE access_counter(
  cnt  INT UNSIGNED NOT NULL 
);

INSERT INTO access_counter VALUES(0);
UPDATE access_counter SET cnt=cnt+1;
SELECT * FROM access_counter;

7.略

8.答:

视图:视图是由查询结果造成的一张虚拟表,是表经过某种运算获得的一个投影。

同一张表能够建立多个视图

存储过程:概念相似于函数,就是把一段代码封装起来,当要执行这一段代码的时候,能够经过调用该存储过程来实现。在封装的语句体里面,

能够同if/else ,case,while等控制结构。

能够进行sql编程。

查看现有的存储过程。

函数:须要先定义,而后调用(使用)。

只是规定,这个函数,必需要返回数据——要有返回值

触发器:(1)触发器是一个特殊的存储过程,它是MySQL在insert、update、delete的时候自动执行的代码块。

(2)触发器必须定义在特定的表上。

(3)自动执行,不能直接调用,

做用:监视某种状况并触发某种操做。

 

9.答:
单列:B+树/哈希索引  --> 查询速度快更新速度慢

    - 普通索引 :加速查找

    - 惟一索引 :加速查询 + 约束(不能重复)

    - 主键索引 :加速查询 + 约束(不能重复) + 不能为空

    - 全文索引 :

多列:遵循最左前缀规则

    - 联合索引 :

    - 联合惟一索引 :

其余:

- 索引合并 :利用多个单例索引查询

    - 覆盖索引 :在索引表中就能将想要的数据查询到

    - 组合索引遵循最左前缀规则

        若是组合索引为:(name,email)

        name and email       -- 使用索引

        name                 -- 使用索引

        email                -- 不使用索引

 

10. 答:

     假设联合索引是state/city/zipCode

那么state就是第一关,city是第二关,zipCode就是第三关

必须匹配了第一关,才能匹配第二关,匹配了第一关和第二关,才能匹配第三关

你不能直接到第二关的

索引的格式就是第一层是state,第二层才是city

多列索引是先按照第一列进行排序,而后在第一列排好序的基础上再对第二列排序,若是没有第一列的话,直接访问第二列,那第二列确定是无序的,直接访问后面的列就用不到索引了

 

11. 答:主键是惟一标识一条记录,不能有重复,不容许为空,表的外键就是另外一表的逐渐,外键能够有重复,能够是空值。

       主键用来保证数据完整性,外键用来和其它表创建联系

       主键只能够有一个,而一个表能够有多个外键。

 

12. 答:数学函数:ABS,BIN,MOD,PI

              聚合函数,AVG,MIN,MAX

              字符串函数,ASCII,CONCAT

              日期和时间函数,DATE_ADD,DATE_SUB

              加密函数

 

13. 答:

一、查询谓词没有使用索引的主要边界,换句话说就是select *,可能会致使不走索引。

好比,你查询的是SELECT * FROM T WHERE Y=XXX;假如你的T表上有一个包含Y值的组合索引,可是优化器会认为须要一行行的扫描会更有效,这个时候,优化器可能会选择TABLE ACCESS FULL,可是若是换成了SELECT Y FROM T WHERE Y = XXX,优化器会直接去索引中找到Y的值,由于从B树中就能够找到相应的值。

 

二、单键值的b树索引列上存在null值,致使COUNT(*)不能走索引。

若是在B树索引中有一个空值,那么查询诸如SELECT COUNT(*) FROM T 的时候,由于HASHSET中不能存储空值的,因此优化器不会走索引,有两种方式可让索引有效,一种是SELECT COUNT(*) FROM T WHERE XXX IS NOT NULL或者把这个列的属性改成not null (不能为空)。

 

三、索引列上有函数运算,致使不走索引

若是在T表上有一个索引Y,可是你的查询语句是这样子SELECT * FROM T WHERE FUN(Y) = XXX。这个时候索引也不会被用到,由于你要查询的列中全部的行都须要被计算一遍,所以,若是要让这种sql语句的效率提升的话,在这个表上创建一个基于函数的索引,好比CREATE INDEX IDX FUNT ON T(FUN(Y));这种方式,等于Oracle会创建一个存储全部函数计算结果的值,再进行查询的时候就不须要进行计算了,由于不少函数存在不一样返回值,所以必须标明这个函数是有固定返回值的。

 

四、隐式转换致使不走索引。

索引不适用于隐式转换的状况,好比你的SELECT * FROM T WHERE Y = 5 在Y上面有一个索引,可是Y列是VARCHAR2的,那么Oracle会将上面的5进行一个隐式的转换,SELECT * FROM T WHERE TO_NUMBER(Y) = 5,这个时候也是有可能用不到索引的。

 

五、表的数据库小或者须要选择大部分数据,不走索引

在Oracle的初始化参数中,有一个参数是一次读取的数据块的数目,好比你的表只有几个数据块大小,并且能够被Oracle一次性抓取,那么就没有使用索引的必要了,由于抓取索引还须要去根据rowid从数据块中获取相应的元素值,所以在表特别小的状况下,索引没有用到是情理当中的事情。

六、cbo优化器下统计信息不许确,致使不走索引

很长时间没有作表分析,或者从新收集表状态信息了,在数据字典中,表的统计信息是不许确的,这个状况下,可能会使用错误的索引,这个效率可能也是比较低的。

七、!=或者<>(不等于),可能致使不走索引,也可能走 INDEX FAST FULL SCAN

例如select id  from test where id<>100

八、表字段的属性致使不走索引,字符型的索引列会致使优化器认为须要扫描索引大部分数据且聚簇因子很大,最终致使弃用索引扫描而改用全表扫描方式,

因为字符型和数值型的在insert的时候排序不一样,字符类型致使了聚簇因子很大,缘由是插入顺序与排序顺序不一样。详细点说,就是按照数字类型插入(1..3200000),按字符类型('1'...'32000000')t排序,在对字符类型使用大于运算符时,会致使优化器认为须要扫描索引大部分数据且聚簇因子很大,最终致使弃用索引扫描而改用全表扫描方式。

 

 

14.答: 

slow_query_log = OFF                 # 是否开启慢日志记录

long_query_time = 2                  # 时间限制,超过此时间,则记录

slow_query_log_file = /usr/slow.log  # 日志文件

log_queries_not_using_indexes = OFF  # 为使用索引的搜索是否记录

 

15. 答:

   MySQL命令行导出数据库

1,进入MySQL目录下的bin文件夹:cd MySQL中到bin文件夹的目录

如我输入的命令行:cd C:\Program Files\MySQL\MySQL Server 4.1\bin

(或者直接将windows的环境变量path中添加该目录)

2,导出数据库:mysqldump -u 用户名 -p 数据库名 > 导出的文件名

如我输入的命令行:mysqldump -u root -p news > news.sql   (输入后会让你输入进入MySQL的密码)

(若是导出单张表的话在数据库名后面输入表名便可)

三、会看到文件news.sql自动生成到bin文件下 

命令行导入数据库

1,将要导入的.sql文件移至bin文件下,这样的路径比较方便
2,同上面导出的第1步
3,进入MySQL:mysql -u 用户名 -p

如我输入的命令行:mysql -u root -p   (输入一样后会让你输入MySQL的密码)

4,在MySQL-Front中新建你要建的数据库,这时是空数据库,如新建一个名为news的目标数据库
5,输入:mysql>use 目标数据库名

如我输入的命令行:mysql>use news;

6,导入文件:mysql>source 导入的文件名;

 

16. 答:

   选取最适用的字段属性。

   使用链接(join)来代替子查询(Sub-Queries)

   使用联合(UNION)来代替手动建立的临时表

   事务

   锁定表

   使用外键

   使用索引

   优化的查询语句

 

 

17. 答:char长度不可变,varchar长度是可变的。char的存取数度仍是要比varchar要快得多,由于其长度固定,方便程序的存储与查找;可是char也为此付出的是空间的代价,由于其长度固定,因此不免会有多余的空格占位符占据空间,可谓是以空间换取时间效率,而varchar是以空间效率为首位的。

再者,char的存储方式是,对英文字符(ASCII)占用1个字节,对一个汉字占用两个字节;而varchar的存储方式是,对每一个英文字符占用2个字节,汉字也占用2个字节。

 

18. 答:

弄明白了explain语法返回的每一项结果,咱们就能知道查询大体的运行时间了,若是查询里没有用到索引、或者须要扫描的行过多,那么能够感到明显的延迟。所以须要改变查询方式或者新建索引。mysql中的explain语法能够帮助咱们改写查询,优化表的结构和索引的设置,从而最大地提升查询效率。固然,在大规模数据量时,索引的创建和维护的代价也是很高的,每每须要较长的时间和较大的空间,若是在不一样的列组合上创建索引,空间的开销会更大。所以索引最好设置在须要常常查询的字段中。

 

19. 答:两个查询语句的区别在于,下面那一句是从从第一行开始查询。

 

20. 答:

        若是使用子查询去优化LIMIT的话,则子查询必须是连续的,某种意义来说,子查询不该该有where条件,where会过滤数据,使数据失去连续性。
   若是你查询的记录比较大,而且数据传输量比较大,好比包含了text类型的field,则能够经过创建子查询。

   SELECT id,title,content FROM items WHERE id IN (SELECT id FROM items ORDER BY id limit 900000, 10);

   若是limit语句的offset较大,你能够经过传递pk键值来减少offset = 0,这个主键最好是int类型而且auto_increment优化方法有子查询优化法,倒排表优化法,反向查找优化法,limit限制优化法,只查优化法。

 

21. 答:

       一、索引合并是把几个索引的范围扫描合并成一个索引。

二、索引合并的时候,会对索引进行并集,交集或者先交集再并集操做,以便合并成一个索引。

三、这些须要合并的索引只能是一个表的。不能对多表进行索引合并。

22. 答:

覆盖索引只是特定于具体select语录而言的联合索引。也就是说一个联合索引对于某个select语句,经过索引能够直接获取查询结果,而再也不须要回表查询啦,就称该联合索引覆盖了这条select语句。

或者: MySQL能够利用索引返回SELECT 列表中的字段。而没必要根据索引再次读取数据文件。包含全部知足查询须要的数据的索引成为覆盖索引(Covering Index)。也就是平时所说的不须要回表操做。

或者:就是select的数据列只用从索引中就可以取得,没必要从数据表中读取,换句话说查询列要被所使用的索引覆盖。

 

23. 答:

       经过设置主从数据库实现读写分离,主数据库负责“写操做”,从数据库负责“读操做”,根据压力状况,从数据库能够部署多个提升“读”的速度,借此来提升系统整体的性能。

要实现读写分离,就要解决主从数据库数据同步的问题,在主数据库写入数据后要保证从数据库的数据也要更新。

 

24.答:

垂直切分

    把不一样功能,不一样模块的数据分别放到不一样的表中,可是若是同一个模块的数据量太大就会存在性能瓶颈

   水平切分

  垂直切分解决不了大表的瓶颈,若是同一个功能中表的数据量过大,就要对该表进行切分,为水平切分

通俗理解:垂直切分---分不一样的模块表;水平切分---分同一个模块下的多个表。

 

25. 答:

一、Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其余东西,例如图片、视频等等;

二、Redis不只仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储;

三、虚拟内存--Redis当物理内存用完时,能够将一些好久没用到的value 交换到磁盘;

四、过时策略--memcache在set时就指定,例如set key1 0 0 8,即永不过时。Redis能够经过例如expire 设定,例如expire name 10;

五、分布式--设定memcache集群,利用magent作一主多从;redis能够作一主多从。均可以一主一从;

六、存储数据安全--memcache挂掉后,数据没了;redis能够按期保存到磁盘(持久化);

七、灾难恢复--memcache挂掉后,数据不可恢复; redis数据丢失后能够经过aof恢复;

八、Redis支持数据的备份,即master-slave模式的数据备份;

 

26. 答:

     默认状况下是十六个。

 

27. 答:安装Redis, import  redis

 

28. 答:

Redis实例须要装载大量用户在短期内产生的数据,数以百万计的keys须要被快速的建立。即大量数据插入(mass insertion)

使用Luke协议

使用正常模式的Redis客户端执行大量数据插入是不明智的:由于一个个的插入会有大量的时间浪费在每个命令往返时间上。 
使用管道(pipelining)还比较靠谱,可是在大量插入数据的同时又须要执行其余新命令时,这时读取数据的同时须要确保尽量快的写入数据。 
只有一小部分的客户端支持非阻塞/输出(non-blocking I/O),而且并非全部客户端能以最大限度的提升吞吐量到高效的方式来分析答复。 

 

同时,在分析回复的时候,咱们会采用计数器的方法计数,以便在最后可以告诉咱们大量插入数据的数据量

 

29. 答:

 

Redis主从复制能够根据是不是全量分为全量同步和增量同步。

1 全量同步

  Redis全量复制通常发生在Slave初始化阶段,这时Slave须要将Master上的全部数据都复制一份。具体步骤以下: 
  1)从服务器链接主服务器,发送SYNC命令; 
  2)主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的全部写命令; 
  3)主服务器BGSAVE执行完后,向全部从服务器发送快照文件,并在发送期间继续记录被执行的写命令; 
  4)从服务器收到快照文件后丢弃全部旧数据,载入收到的快照; 
  5)主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令; 
  6)从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令; 

2 增量同步

  Redis增量复制是指Slave初始化后开始正常工做时主服务器发生的写操做同步到从服务器的过程。 
增量复制的过程主要是主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令。

Redis的正常部署中通常都是一个master用于写操做,若干个slave用于读操做,另外按期的数据备份操做也是单独选址一个slave完成,这样能够最大程度发挥出redis的性能。在部署完成,各master\slave程序启动以后,首先进行第一阶段初始化时的全同步操做,全同步操做完成以后,后续全部写操做都是在master上进行,全部读操做都是在slave上进行,所以用户的写操做须要及时扩散到全部的slave以便保持数据最大程度上的同步。

 

30. 答:

Redis-Sentinel是Redis官方推荐的高可用性(HA)解决方案,当用Redis作Master-slave的高可用方案时,假如master宕机了,Redis自己(包括它的不少客户端)都没有实现自动进行主备切换,而Redis-sentinel自己也是一个独立运行的进程,它能监控多个master-slave集群,发现master宕机后能进行自动切换。

它的主要功能有如下几点

不时地监控redis是否按照预期良好地运行;

若是发现某个redis节点运行出现情况,可以通知另一个进程(例如它的客户端);

可以进行自动切换。当一个master节点不可用时,可以选举出master的多个slave(若是有超过一个slave的话)中的一个来做为新的master,其它的slave节点会将它所追随的master的地址改成被提高为master的slave的新地址。

31.答:

       1.客户端分片

  客户端分片是把分片的逻辑放在Redis客户端实现,经过Redis客户端预先定义好的路由规则,把对Key的访问转发到不一样的Redis实例中,最后把返回结果聚集。

 2.Twemproxy

  Twemproxy是由Twitter开源的Redis代理,其基本原理是:Redis客户端把请求发送到Twemproxy,Twemproxy根据路由规则发送到正确的Redis实例,最后Twemproxy把结果聚集返回给客户端。

  Twemproxy经过引入一个代理层,将多个Redis实例进行统一管理,使Redis客户端只须要在Twemproxy上进行操做,而不须要关心后面有多少个Redis实例,从而实现了Redis集群。

3.Codis

  Twemproxy不能平滑增长Redis实例的问题带来了很大的不便,因而豌豆荚自主研发了Codis,一个支持平滑增长Redis实例的Redis代理软件,其基于Go和C语言开发,并于2014年11月在GitHub上开源。

  Codis包含下面4个部分。

Codis Proxy:Redis客户端链接到Redis实例的代理,实现了Redis的协议,Redis客户端链接到Codis Proxy进行各类操做。Codis Proxy是无状态的,能够用Keepalived等负载均衡软件部署多个Codis Proxy实现高可用。

CodisRedis:Codis项目维护的Redis分支,添加了slot和原子的数据迁移命令。Codis上层的 Codis Proxy和Codisconfig只有与这个版本的Redis通讯才能正常运行。

Codisconfig:Codis管理工具。能够执行添加删除CodisRedis节点、添加删除Codis Proxy、数据迁移等操做。另外,Codisconfig自带了HTTP server,里面集成了一个管理界面,方便运维人员观察Codis集群的状态和进行相关的操做,极大提升了运维的方便性,弥补了Twemproxy的缺点。

ZooKeeper:分布式的、开源的应用程序协调服务,是Hadoop和Hbase的重要组件,其为分布式应用提供一致性服务,提供的功能包括:配置维护、名字服务、分布式同步、组服务等。Codis依赖于ZooKeeper存储数据路由表的信息和Codis Proxy节点的元信息。另外,Codisconfig发起的命令都会经过ZooKeeper同步到CodisProxy的节点。

4.Redis 3.0集群

  Redis 3.0集群采用了P2P的模式,彻底去中心化。Redis把全部的Key分红了16384个slot,每一个Redis实例负责其中一部分slot。集群中的全部信息(节点、端口、slot等),都经过节点之间按期的数据交换而更新。

Redis客户端在任意一个Redis实例发出请求,若是所需数据不在该实例中,经过重定向命 

 5.云服务器上的集群服务

  国内的云服务器提供商阿里云、UCloud等均推出了基于Redis的云存储服务。

令引导客户端访问所需的实例。

 

32. 答:默认有16384个哈希槽

33. 答:

Redis的持久化策略:2种

 ---------rdb:快照形式是直接把内存中的数据保存到一个dump文件中,定时保存,保存策略

这种方式不能彻底保证数据持久化,由于是定时保存,因此当redis服务down掉,就会丢失一部分数据,并且数据量大,写操做多的状况下,会引发大量的磁盘IO操做,会影响性能。

 ---------aof:把全部的对redis的服务器进行修改的命令都存到一个文件里,命令的集合

使用aof作持久化,每个写命令都经过write函数追加到appendonly.aof中.

配置方式:启动aof持久化的方式 

34.  答:

定时删除

含义:在设置key的过时时间的同时,为该key建立一个定时器,让定时器在key的过时时间来临时,对key进行删除

优势:保证内存被尽快释放

缺点:

若过时key不少,删除这些key会占用不少的CPU时间,在CPU时间紧张的状况下,CPU不能把全部的时间用来作要紧的事儿,还须要去花时间删除这些key

定时器的建立耗时,若为每个设置过时时间的key建立一个定时器(将会有大量的定时器产生),性能影响严重

没人用

惰性删除

含义:key过时的时候不删除,每次从数据库获取key的时候去检查是否过时,若过时,则删除,返回null。

优势:删除操做只发生在从数据库取出key的时候发生,并且只删除当前key,因此对CPU时间的占用是比较少的,并且此时的删除是已经到了非作不可的地步(若是此时还不删除的话,咱们就会获取到了已通过期的key了)

缺点:若大量的key在超出超时时间后,好久一段时间内,都没有被获取过,那么可能发生内存泄露(无用的垃圾占用了大量的内存)

按期删除

含义:每隔一段时间执行一次删除过时key操做

优势:

经过限制删除操做的时长和频率,来减小删除操做对CPU时间的占用--处理"定时删除"的缺点

按期删除过时key--处理"惰性删除"的缺点

缺点

在内存友好方面,不如"定时删除"

在CPU时间友好方面,不如"惰性删除"

难点

合理设置删除操做的执行时长(每次删除执行多长时间)和执行频率(每隔多长时间作一次删除)(这个要根据服务器运行状况来定了)

 

 

 

35. 答:

redis 内存数据集大小上升到必定大小的时候,就会施行数据淘汰策略。redis 提供 6种数据淘汰策略:
volatile-lru:从已设置过时时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过时时间的数据集(server.db[i].expires)中挑选将要过时的数据淘汰
volatile-random:从已设置过时时间的数据集(server.db[i].expires)中任意选择数据淘汰
allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
no-enviction(驱逐):禁止驱逐数据

 

36.略

37.答:

Redis提供了两种方式来做消息队列。 
一个是使用生产者消费模式模式, 
另外一个就是发布订阅者模式。 
前者会让一个或者多个客户端监听消息队列,一旦消息到达,消费者立刻消费,谁先抢到算谁的,若是队列里没有消息,则消费者继续监听。 
后者也是一个或多个客户端订阅消息频道,只要发布者发布消息,全部订阅者都能收到消息,订阅者都是平等的。

 

38.答:

  “发布/订阅”模式包含两种角色,分别是发布者和订阅者。订阅者能够订阅一个或若干个频道(channel),而发布者能够向指定的频道发送消息,全部订阅此频道的订阅者都会收到此消息。

     发布者发送消息的命令是PUBLISH,用法是PUBLISH channel message,如向channel.1说一声“hi”:

        redis>PUBLISH channel.1 hi

        (integer)  0

      这样消息就发出去了。返回值表示接收到这条消息的订阅者数量。发出去的消息不会被持久化,也就是说当客户端订阅channel.1后只能收到后续发布到该频道的消息,以前发送到就收不到了。

       订阅频道的命令是SUBSCRIBE,能够同时订阅多个频道,用法是 SUBSCRIBE channel [channel ...]。

        redis>SUBSCRIBE channel.1

        Reading messages... (press Ctrl-C to quit)

        1) "subscribe"

        2) "channel.1"  

        3) (integer) 1

        执行SUBSCRIBE命令后进入订阅状态,处于此状态下客户端不能使用除SUBSCRIBE/UNSUBSCRIBE/PSUBSCRIBE/PUNSUBSCRIBE这四个属于“发布/订阅”模式以外的命令,不然会报错。

        进入订阅模式后客户端可能收到三种类型的回复。每种类型的回复都包含3个值,第一个值是消息的类型,根据消息类型的不一样,第二第三个值的含义也不一样。消息类型可能的取值有:

        (1)Subscribe。表示订阅成功的反馈信息。第二个值是订阅成功的频道名称,第三个值是当前客户端订阅的频道数。

        (2)message。这个类型的回复表示收到的消息。第二个值表示产生消息的频道名称,第三个值是消息内容。

        (3)unsubscribe。表示成功取消订阅某个频道。第二个值是对应的频道名称,第三个值是当前客户端订阅的频道数量,当此值为0时客户端会退出订阅状态。

 

 

39. 答:

Codis 是一个分布式 Redis 解决方案, 对于上层的应用来讲, 链接到 Codis Proxy 和链接原生的 Redis Server 没有明显的区别 (不支持的命令列表), 上层应用能够像使用单机的 Redis 同样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工做, 全部后边的一切事情, 对于前面的客户端来讲是透明的, 能够简单的认为后边链接的是一个内存无限大的 Redis 服务.

 

 

40. 答:

Twemproxy 也叫 nutcraker。是 Twtter 开源的一个 Redis 和 Memcache 代理服务器,主要用于管理 Redis 和 Memcached 集群,减小与Cache 服务器直接链接的数量。

Twemproxy特性:

轻量级、快速

保持长链接

减小了直接与缓存服务器链接的链接数量

使用 pipelining 处理请求和响应

支持代理到多台服务器上

同时支持多个服务器池

自动分片数据到多个服务器上

实现完整的 memcached 的 ASCII 和再分配协议

经过 yaml 文件配置服务器池

支持多个哈希模式,包括一致性哈希和分布

可以配置删除故障节点

能够经过端口监控状态

支持 linux, *bsd,os x 和 solaris

 

 

41.答:

class CasNormal(object):

  def __init__(self, host, key):

    self.r = redis.Redis(host)

    self.key = key

    if not self.r.exists(self.key):

      self.r.set(self.key, 0)

 

  def inc(self):

    with self.r.pipeline() as pipe:

      while True:

        try:

          #监视一个key,若是在执行期间被修改了,会抛出WatchError

          pipe.watch(self.key)

          next_count = 30 + int(pipe.get(self.key))

          pipe.multi()

          if next_count < int(time.time()):

            next_count = int(time.time())

          pipe.set(self.key, next_count)

          pipe.execute()

          return next_count

        except WatchError:

          continue

        finally:

          pipe.reset()

 

42.答:Redis Watch 命令用于监视一个(或多个) key ,若是在事务执行以前这个(或这些) key 被其余命令所改动,那么事务将被打断

 

43.略

44.答:

分布式锁应该具备的特性(Safety & Liveness)

咱们将从三个特性的角度出发来设计RedLock模型:

安全性(Safety):在任意时刻,只有一个客户端能够得到锁(排他性)。

避免死锁:客户端最终必定能够得到锁,即便锁住某个资源的客户端在释放锁以前崩溃或者网络不可达。

容错性:只要Redsi集群中的大部分节点存活,client就能够进行加锁解锁操做。


一个Client想要得到一个锁须要如下几个操做:

获得本地时间

Client使用相同的key和随机数,按照顺序在每一个Master实例中尝试得到锁。在得到锁的过程当中,为每个锁操做设置一个快速失败时间(若是想要得到一个10秒的锁, 那么每个锁操做的失败时间设为5-50ms)。
这样能够避免客户端与一个已经故障的Master通讯占用太长时间,经过快速失败的方式尽快的与集群中的其余节点完成锁操做。

客户端计算出与master得到锁操做过程当中消耗的时间,当且仅当Client得到锁消耗的时间小于锁的存活时间,而且在一半以上的master节点中得到锁。才认为client成功的得到了锁。

若是已经得到了锁,Client执行任务的时间窗口是锁的存活时间减去得到锁消耗的时间。

若是Client得到锁的数量不足一半以上,或得到锁的时间超时,那么认为得到锁失败。客户端须要尝试在全部的master节点中释放锁, 即便在第二步中没有成功得到该Master节点中的锁,仍要进行释放操做。



45.答:

一致性哈希要对缓存的key进行哈希,同时也须要服务器也提供一个key进行哈希,而后将其分布在一个闭圆上,在决定一个key的分布的时候,这里经过找到第一个大于这个key的哈希值的服务器就好了。。。

这样在当一台服务器退出以后,或者有新的服务器加入进来以后,只会影响一部分的key的哈希分布,不至于致使全部的key的哈希分布都失效。

46. 答:获取指定前缀的key:redis-cli KEYS “oldboy*”

相关文章
相关标签/搜索