面试题-数据库和缓存(46题)(待完善)

  1. 列举常见的关系型数据库和非关系型都有那些?

    关系型数据库
    Oracle、DB2、Microsoft SQL Server、Microsoft Access、MySQL 
    非关系型
    NoSql、Cloudant、MongoDb、redis、HBase
    关系型数据库
      关系型数据库的特性
      1、关系型数据库,是指采用了关系模型来组织数据的数据库;
      2、关系型数据库的最大特点就是事务的一致性;
      3、简单来说,关系模型指的就是二维表格模型,而一个关系型数据库就是由二维表及其之间的联系所组成的一个数据组织。
      关系型数据库的优点
      1、容易理解:二维表结构是非常贴近逻辑世界一个概念,关系模型相对网状、层次等其他模型来说更容易理解; 
      2、使用方便:通用的SQL语言使得操作关系型数据库非常方便; 
      3、易于维护:丰富的完整性(实体完整性、参照完整性和用户定义的完整性)大大减低了数据冗余和数据不一致的概率; 
      4、支持SQL,可用于复杂的查询。
      关系型数据库的缺点
      1、为了维护一致性所付出的巨大代价就是其读写性能比较差; 
      2、固定的表结构; 
      3、高并发读写需求; 
      4、海量数据的高效率读写;
    
    非关系型数据库
      非关系型数据库的特性
      1、使用键值对存储数据; 
      2、分布式; 
      3、一般不支持ACID特性; 
      4、非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合。
      非关系型数据库的优点
      1、无需经过sql层的解析,读写性能很高; 
      2、基于键值对,数据没有耦合性,容易扩展; 
      3、存储数据的格式:nosql的存储格式是key,value形式、文档形式、图片形式等等,文档形式、图片形式等等,而关系型数据库则只支持基础类型。
      非关系型数据库的缺点
       1、不提供sql支持,学习和使用成本较高; 
       2、无事务处理,附加功能bi和报表等支持也不好;
    
  2. MySQL常见数据库引擎及比较?

    MyISAM:默认的MySQL插件式存储引擎,它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一。
    注意,通过更改STORAGE_ENGINE配置变量,能够方便地更改MySQL服务器的默认存储引擎。
      InnoDB:用于事务处理应用程序,具有众多特性,包括ACID事务支持。(提供行级锁)
      BDB:可替代InnoDB的事务引擎,支持COMMIT、ROLLBACK和其他事务特性。
      Memory:将所有数据保存在RAM中,在需要快速查找引用和其他类似数据的环境下,可提供极快的访问。
      Merge:允许MySQL DBA或开发人员将一系列等同的MyISAM表以逻辑方式组合在一起,并作为1个对象引用它们。对于诸如数据仓储等VLDB环境十分适合。
      Archive:为大量很少引用的历史、归档、或安全审计信息的存储和检索提供了完美的解决方案。
      Federated:能够将多个分离的MySQL服务器链接起来,从多个物理服务器创建一个逻辑数据库。十分适合于分布式环境或数据集市环境。
      Cluster/NDB:MySQL的簇式数据库引擎,尤其适合于具有高性能查找要求的应用程序,
    这类查找需求还要求具有最高的正常工作时间和可用性。
      Other:其他存储引擎包括CSV(引用由逗号隔开的用作数据库表的文件),
    Blackhole(用于临时禁止对数据库的应用程序输入),以及Example引擎
    (可为快速创建定制的插件式存储引擎提供帮助)。
    
  3. 简述数据三大范式?

    第一范式
    1、每一列属性都是不可再分的属性值,确保每一列的原子性
    2、两列的属性相近或相似或一样,尽量合并属性一样的列,确保不产生冗余数据。
    第二范式
    每一行的数据只能与其中一列相关,即一行数据只做一件事。只要数据列中出现数据重复,就要把表拆分开来。
    第三范式
    数据不能存在传递关系,即没个属性都跟主键有直接关系而不是间接关系。
    像:a-->b-->c 属性之间含有这样的关系,是不符合第三范式的。
    
  4. 什么是事务?MySQL如何支持事务?

    事务是由一步或几步数据库操作序列组成逻辑执行单元,这系列操作要么全部执行,要么全部放弃执行。
    程序和事务是两个不同的概念。一般而言:一段程序中可能包含多个事务。
    (说白了就是几步的数据库操作而构成的逻辑执行单元)
    事务具有四个特性:原子性(Atomicity)、一致性(Consistency)、
    隔离性(Isolation)和持续性(Durability)。这四个特性也简称ACID性。
    
    MYSQL的事务处理主要有两种方法
      1.用begin,rollback,commit来实现
        begin开始一个事务
        rollback事务回滚
       commit 事务确认
      2.直接用set来改变mysql的自动提交模式
       mysql默认是自动提交的,也就是你提交一个query,就直接执行!可以通过
       set autocommit = 0 禁止自动提交
       set autocommit = 1 开启自动提交
    
  5. 简述数据库设计中一对多和多对多的应用场景?

    数据库实体间有三种对应关系:一对一,一对多,多对多。
           一对一关系示例:
    一个学生对应一个学生档案材料,或者每个人都有唯一的身份证编号。
           一对多关系示例:
    一个学生只属于一个班,但是一个班级有多名学生。
           多对多关系示例:
    一个学生可以选择多门课,一门课也有多名学生。
    
  6. 如何基于数据库实现商城商品计数器?

    创建一个商城表---包含(id,商品名,每一个商品对应数量)
    
  7. 常见SQL(必备)
    详见武沛齐博客:https://www.cnblogs.com/wupeiqi/articles/5729934.html

  8. 简述触发器、函数、视图、存储过程?

    触发器:触发器是一个特殊的存储过程,它是MySQL在insert、update、delete的时候自动执行的代码块。
    函数:MySQL中提供了许多内置函数,还可以自定义函数(实现程序员需要sql逻辑处理)
    视图:视图是由查询结果形成的一张虚拟表,是表通过某种运算得到的一个投影
    存储过程:把一段代码封装起来,当要执行这一段代码的时候,可以通过调用该存储过程来实现
    (经过第一次编译后再次调用不需要再次编译,比一个个执行sql语句效率高)
    
  9. MySQL索引种类

    索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),更通俗的说,
    数据库索引好比是一本书前面的目录,能加快数据库的查询速度MySQL索引的类型:   
    1. 普通索引:这是最基本的索引,它没有任何限制   
    2.唯一索引:索引列的值必须唯一,但允许有空值,如果是组合索引,则列值的组合必须唯一   
    3.全文索引:全文索引仅可用于 MyISAM 表,可以从CHAR、VARCHAR或TEXT列中作为
    CREATE TABLE语句的一部分被创建,或是随后使用ALTER TABLE 或CREATE INDEX被添加 
    (切记对于大容量的数据表,生成全文索引是一个非常消耗时间非常消耗硬盘空间的做法)   
    4. 单列索引、多列索引:多个单列索引与单个多列索引的查询效果不同,
    因为执行查询时,MySQL只能使用一个索引,会从多个索引中选择一个限制最为严格的索引。   
    5.组合索引(最左前缀):简单的理解就是只从最左面的开始组合(
    实在单列索引的基础上进一步压榨索引效率的一种方式 
    
  10. 索引在什么情况下遵循最左前缀的规则?

    mysql在使用组合索引查询的时候需要遵循“最左前缀”规则
    
    
  11. 主键和外键的区别?

    1.主键是能确定一条记录的唯一标识
    2.外键用于与另一张表的关联,是能确定另一张表记录的字段,用于保持数据的一致性
    
    
  12. MySQL常见的函数?

    聚合函数:   
    AVG(col)返回指定列的平均值   
    COUNT(col)返回指定列中非NULL值的个数   
    MIN(col)返回指定列的最小值   
    MAX(col)返回指定列的最大值   
    SUM(col)返回指定列的所有值之和   
    GROUP_CONCAT(col) 返回由属于一组的列值连接组合而成的结果
    数学函数:   
    ABS(x) 返回x的绝对值   
    BIN(x) 返回x的二进制(OCT返回八进制,HEX返回十六进制)
    
    
  13. 列举 创建索引但是无法命中索引的8种情况。

    1.如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因)
    2.对于多列索引,不是使用的第一部分,则不会使用索引
    3.like查询是以%开头
    4.如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引
    5.如果mysql估计使用全表扫描要比使用索引快,则不使用索引
    6 对小表查询
    7 提示不使用索引
    8 统计数据不真实
    9.单独引用复合索引里非第一位置的索引列.
    
    
  14. 如何开启慢日志查询?

    1 执行 SHOW VARIABLES LIKE “%slow%”,获知 mysql 是否开启慢查询 slow_query_log 
    慢查询开启状态 OFF 未开启 ON 为开启 slow_query_log_file 慢查询日志存放的位置(
    这个目录需要MySQL的运行帐号的可写权限,一般设置为MySQL的数据存放目录)
    2 修改配置文件( 放在[mysqld]下),重启 long_query_time 查询超过多少秒才记录
    3 测试是否成功
    4 慢查询日志文件的信息格式
    
    
  15. 数据库导入导出命令(结构+数据)?

    1.导出整个数据库   mysqldump -u用户名 -p密码 数据库名 > 导出的文件名   
    例如:C:\Users\jack> mysqldump -uroot -pmysql sva_rec > e:\sva_rec.sql   
    2.导出一个表,包括表结构和数据   mysqldump -u用户名 -p 密码 数据库名 表名> 导出的文件名   
    例如:C:\Users\jack> mysqldump -uroot -pmysql sva_rec date_rec_drv> e:\date_rec_drv.sql   
    3.导出一个数据库结构   
    例如:C:\Users\jack> mysqldump -uroot -pmysql -d sva_rec > e:\sva_rec.sql
    4.导出一个表,只有表结构   mysqldump -u用户名 -p 密码 -d数据库名 表名> 导出的文件名     
    例如:C:\Users\jack> mysqldump -uroot -pmysql -d sva_rec date_rec_drv> e:\date_rec_drv.sql   
    5.导入数据库   常用source 命令   进入mysql数据库控制台,   
    如mysql -u root -p   mysql>use 数据库   然后使用source命令,后面参数为脚本文件(如这里用到的.sql)   
    mysql>source d:wcnc_db.sql
    
    
  16. 数据库优化方案?

    总体思路从以下几个方面:
    1、选取最适用的字段属性
    2、使用连接(JOIN)来代替子查询(Sub-Queries)
    3、使用联合(UNION)来代替手动创建的临时表
    4、事务(当多个用户同时使用相同的数据源时,它可以利用锁定数据库的方法来为用户提供一种安全的访问方式,
    这样可以保证用户的操作不被其它的用户所干扰)
    5.锁定表(有些情况下我们可以通过锁定表的方法来获得更好的性能)
    6、使用外键(锁定表的方法可以维护数据的完整性,但是它却不能保证数据的关联性。
    这个时候我们就可以使用外键)
    7、使用索引
    8、优化的查询语句(绝大多数情况下,使用索引可以提高查询的速度,但如果SQL语句使用不恰当的话,索引将无法发挥它应有的作用)
    
    
  17. char和varchar的区别?

    char:定长,char的存取数度相对快
    varchar:不定长,存取速度相对
    
    
  18. 简述MySQL的执行计划?

    执行计划explain命令是查看查询优化器如何决定执行查询的主要方法。
    这个功能有局限性,并不总会说出真相,但它的输出是可以获取的最好信息,通过输出结果反推执行过程
    
    
  19. 在对name做了唯一索引前提下,简述以下区别:

    select * from tb where name = ‘Oldboy-Wupeiqi’ 

    select * from tb where name = ‘Oldboy-Wupeiqi’ limit 1

    select * from tb where name = ‘Oldboy-Wupeiqi’ 
 
    select * from tb where name = ‘Oldboy-Wupeiqi’ limit 1
    select * from tb where name = ‘Oldboy’ -------------
    查找到tb表中所有name = ‘Oldboy’的数据
    select * from tb where name = ‘Oldboy’ limit 1------
    查找到tb表中所有name = ‘Oldboy’的数据只取其中的第一条
    
    
  20. 1000w条数据,使用limit offset 分页时,为什么越往后翻越慢?如何解决?

    当一个数据库表过于庞大,LIMIT offset, length中的offset值过大,则SQL查询语句会非常缓慢,
    你需增加order by,并且order by字段需要建立索引。
    
    
  21. 什么是索引合并?

    1.索引合并是把几个索引的范围扫描合并成一个索引。
    2、索引合并的时候,会对索引进行并集,交集或者先交集再并集操作,以便合并成一个索引。
    3、这些需要合并的索引只能是一个表的。不能对多表进行索引合并。
    
    
  22. 什么是覆盖索引?

    覆盖索引又可以称为索引覆盖。
      解释一: 就是select的数据列只用从索引中就能够取得,不必从数据表中读取,
    换句话说查询列要被所使用的索引覆盖。
      解释二: 索引是高效找到行的一个方法,当能通过检索索引就可以读取想要的数据,
    那就不需要再到数据表中读取行了。如果一个索引包含了(或覆盖了)满足查询语句中字段
    与条件的数据就叫做覆盖索引。
      解释三: 是非聚集组合索引的一种形式,它包括在查询里的Select、Join和Where子句用到的所有列
    (即建立索引的字段正好是覆盖查询语句[select子句]与查询条件[Where子句]中所涉及的字段,
    也即,索引包含了查询正在查找的所有数据)。
    
    
  23. 简述数据库读写分离?

    读写分离从字面意思就可以理解,就是把对数据库的读操作和写操作分离开。
    读写分离在网站发展初期可以一定程度上缓解读写并发时产生锁的问题,
    将读写压力分担到多台服务器上,通常用于读远大于写的场景。
    *读写分离的好处*
    1)数据是网站的生命,读写分离通过主从备份数据,保证了系统的冗余,保护了珍贵的数据。
    2)提高了系统性能,一定程度提高了数据库负载能力。
    *适用读写分离场景*
    1)网站初期想要缓解数据负载最简单可行的方案。
    2)服务器面对的是读远大于写的场景,并且业务能够允许时间上一些延迟。
    *读写分离实现方式*
    目前读写分离方案网上找了几个并做了对比。
    1.mycat 基于阿里的cobar改版的(比较稳定,论坛活跃)
    2.atlas 360开发的 网友说不是很稳定 (已经很久没更新)
    3.mysql-proxy mysql自带 (不是很稳定)
    4.oneproxy 比较稳定 性能也很好 (需要付费)
    5.amoeba 好像还行,有一些公司使用 (但是很久没有更新了)
    
    
  24. 简述数据库分库分表?(水平、垂直)

    从字面上简单理解,就是把原本存储于一个库的数据分块存储到多个库上,
    把原本存储于一个表的数据分块存储到多个表上。
    
    数据库中的数据量不一定是可控的,在未进行分库分表的情况下,随着时间和业务的发展,
    库中的表会越来越多,表中的数据量也会越来越大,相应地,数据操作,增删改查的开销也会越来越大;
    另外,由于无法进行分布式式部署,而一台服务器的资源(CPU、磁盘、内存、IO等)是有限的,
    最终数据库所能承载的数据量、数据处理能力都将遭遇瓶颈。
    
    分库分表有垂直切分和水平切分两种。
    何谓垂直切分,即将表按照功能模块、关系密切程度划分出来,部署到不同的库上。
    例如,我们会建立定义数据库workDB、商品数据库payDB、用户数据库userDB、日志数据库logDB等,
    分别用于存储项目数据定义表、商品定义表、用户数据表、日志数据表等。
    
    
    何谓水平切分,当一个表中的数据量过大时,我们可以把该表的数据按照某种规则,
    例如userID散列,进行划分,然后存储到多个结构相同的表,和不同的库上。
    例如,我们的userDB中的用户数据表中,每一个表的数据量都很大,
    就可以把userDB切分为结构相同的多个userDB:part0DB、part1DB等,
    再将userDB上的用户数据表userTable,切分为很多userTable:userTable0、userTable1等,
    然后将这些表按照一定的规则存储到多个userDB上。
    
    
  25. redis和memcached比较?

    1、Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其他东西。例如图片、视频等等;
    2、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储;
    3、虚拟内存--Redis当物理内存用完时,可以将一些很久没用到的value
    交换到磁盘;
    4、过期策略--memcache在set时就指定,例如set key1 0 0 8,即永不过期。Redis可以通过例如expire 设定,
    例如expire name 10;
    5、分布式--设定memcache集群,利用magent做一主多从;redis可以做一主多从。都可以一主一从;
    6、存储数据安全--memcache挂掉后,数据没了;redis可以定期保存到磁盘(持久化);
    7、灾难恢复--memcache挂掉后,数据不可恢复;
    redis数据丢失后可以通过aof恢复;
    8、Redis支持数据的备份,即master-slave模式的数据备份;
    9、应用场景不一样:Redis出来作为NoSQL数据库使用外,还能用做消息队列、数据堆栈和数据缓存等;
    Memcached适合于缓存SQL语句、数据集、用户临时性数据、延迟查询数据和session等。
    
    
  26. redis中数据库默认是多少个db 及作用?

    #redis默认有16个db,db0~db15(可以通过配置文件支持更多,无上限)
    并且每个数据库的数据是隔离的不能共享
    可以随时使用SELECT命令更换数据库:redis> SELECT 1#
    注意: 
    多个数据库之间并不是完全隔离的
    比如FLUSHALL命令可以清空一个Redis实例中所有数据库中的数据。
    
    
  27. python操作redis的模块?

    1、基本操作
    redis提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。
    redis连接实例是线程安全的,可以直接将redis连接实例设置为一个全局变量,直接使用。如果需要另一个Redis实例(or Redis数据库)时,就需要重新创建redis连接实例来获取一个新的连接。同理,python的redis没有实现select命令。
    连接redis,加上decode_responses=True,写入的键值对中的value为str类型,不加这个参数写入的则为字节类型。
    连接池
    (1)redis-py使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认,每个Redis实例都会维护一个自己的连接池。
    可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池
    3、管道
    redis默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,
    如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作。
    管道(pipeline)是redis在提供单个请求中缓冲多条服务器命令的基类的子类。它通过减少服务器-客户端之间反复的TCP数据库包,从而大大提高了执行批量命令的功能。
    4、发布订阅
    
    
  28. 如果redis中的某个列表中的数据量非常大,如果实现循环显示每一个值?

    通过scan_iter分片取,减少内存压力
    scan_iter(match=None, count=None)增量式迭代获取redis里匹配的的值# match,匹配指定key
    # count,每次分片最少获取个数
    r = redis.Redis(connection_pool=pool)
    for key in r.scan_iter(match='PREFIX_*', count=100000):
    print(key)
    
    
  29. redis如何实现主从复制?以及数据同步机制?

    Redis中的主从复制,也就是Master-Slave模型,其实现相对比较简单,一般使用在多个Redis实例间
    的数据同步以及Redis集群中用的比较多。
    Redis的主从同步机制可以确保redis的master和slave之间的数据同步。按照同步内容的多少可以分为
    全同步和部分同步;按照同步的时机可以分为slave刚启动时的初始化同步和正常运行过程中的数据
    修改同步;本文将对这两种机制的流程进行分析。
    # 实现主从复制
    '创建6379和6380配置文件'
    redis.conf:6379为默认配置文件,作为Master服务配置;
    redis_6380.conf:6380为同步配置,作为Slave服务配置;
    '配置slaveof同步指令'
    在Slave对应的conf配置文件中,添加以下内容:
    slaveof 127.0.0.1 6379# 数据同步步骤:
    (1)Slave服务器连接到Master服务器.
    (2)Slave服务器发送同步(SYCN)命令.
    (3)Master服务器备份数据库到文件.
    (4)Master服务器把备份文件传输给Slave服务器.
    (5)Slave服务器把备份文件数据导入到数据库中.
    
    
  30. redis中的sentinel的作用?

    Redis SentinelSentinel(哨兵)是用于监控redis集群中Master状态的工具,其已经被集成在redis2.4+的版本中。
    Sentinel作用:
      1):Master状态检测
      2):如果Master异常,则会进行Master-Slave切换,将其中一个Slave作为Master,将之前的Master作为Slave
      3):Master-Slave切换后,master_redis.conf、slave_redis.conf和sentinel.conf的内容都会发生改变,
    即master_redis.conf中会多一行slaveof的配置,sentinel.conf的监控目标会随之调换
    
    
  31. 如何实现redis集群?

    #基于【分片】来完成。
    - 集群是将你的数据拆分到多个Redis实例的过程
    - 可以使用很多电脑的内存总和来支持更大的数据库。
    - 没有分片,你就被局限于单机能支持的内存容量。#redis将所有能放置数据的地方创建了 16384 个哈希槽。
    #如果设置集群的话,就可以为每个实例分配哈希槽:
    - 192.168.1.20【0-5000】
    - 192.168.1.21【5001-10000】
    - 192.168.1.22【10001-16384】#以后想要在redis中写值时:set k1 123 
    - 将k1通过crc16的算法转换成一个数字,然后再将该数字和16384求余,
    - 如果得到的余数 3000,那么就将该值写入到 192.168.1.20 实例中。#集群方案:
    - redis cluster:官方提供的集群方案。
    - codis:豌豆荚技术团队。
    - tweproxy:Twiter技术团队
    
    
    通常有3个途径:官方Redis Cluster;通过Proxy分片;客户端分片(Smart Client)
    Redis Cluster(官方):虽然正式版发布已经有一年多的时间,但还缺乏最佳实践;
    对协议进行了较大修改,导致主流客户端也并非都已支持,部分支持的客户端也没有经过大规模生产环境的验证;
    无中心化设计使整个系统高度耦合,导致很难对业务进行无痛的升级。
    Proxy:现在很多主流的Redis集群都会使用Proxy方式,例如早已开源的Codis。这种方案有很多优点,
    因为支持原声redis协议,所以客户端不需要升级,对业务比较友好。并且升级相对平滑,可以起多个Proxy后,
    逐个进行升级。但是缺点是,因为会多一次跳转,平均会有30%左右的性能开销。
    而且因为原生客户端是无法一次绑定多个Proxy,连接的Proxy如果挂了还是需要人工参与。除非类似Smart
    Client一样封装原有客户端,支持重连到其他Proxy,但这也就带来了客户端分片方式的一些缺点。并且虽然Proxy可以使用多个,并且可以动态增加proxy增加性能,但是所有客户端都是共用所有proxy,那么一些异常的服务有可能影响到其他服务。为每个服务独立搭建proxy,也会给部署带来额外的工作。而我们选择了第三种方案,客户端分片(SmartClient)。客户端分片相比Proxy拥有更好的性能,及更低的延迟。当然也有缺点,就是升级需要重启客户端,而且我们需要维护多个语言的版本,但我们更爱高性能。
    
    
  32. redis中默认有多少个哈希槽?

    Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.
    集群的每个节点负责一部分hash槽
    
    
  33. 简述redis的有哪几种持久化策略及比较?

    #RDB:每隔一段时间对redis进行一次持久化。
    - 缺点:数据不完整
    - 优点:速度快
    #AOF:把所有命令保存起来,如果想重新生成到redis,那么就要把命令重新执行一次。
    - 缺点:速度慢,文件比较大
    - 优点:数据完整
    
    
    Redis的持久化策略:2种
        ---------rdb:快照形式是直接把内存中的数据保存到一个dump文件中,定时保存,保存策略
        ---------aof:把所有的对redis的服务器进行修改的命令都存到一个文件里,命令的集合
    RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,
    先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
    AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录
    
    
  34. 列举redis支持的过期策略。

    maxmemory-policy 六种方式
    volatile-lru:只对设置了过期时间的key进行LRU(默认值) 
    allkeys-lru : 删除lru算法的key   
    volatile-random:随机删除即将过期key   
    allkeys-random:随机删除   
    volatile-ttl : 删除即将过期的   
    noeviction : 永不过期,返回错误  
    
    
  35. MySQL 里有 2000w 数据,redis 中只存 20w 的数据,如何保证 redis 中都是热点数据?

    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(驱逐):禁止驱逐数据
    
    
    # 限定Redis占用的内存,根据自身数据淘汰策略,淘汰冷数据,把热数据加载到内存。
    # 计算一下 20W 数据大约占用的内存,然后设置一下Redis内存限制即可。
    
    
  36. 写代码,基于redis的列表实现 先进先出、后进先出队列、优先级队列。

  37. 如何基于redis实现消息队列?

    可以利用redis存储数据类型的list类型实现消息发送与消费的一对一模式,使用lpush向list的左端推送数据(发送消息),使用rpop从右端接收数据(消费消息)。由于rpop需要周期性的从list中获取数据,可以考虑使用brpop代替rpop,brpop是一个阻塞方法,直到获取到数据
    # 通过发布订阅模式的PUB、SUB实现消息队列
    # 发布者发布消息到频道了,频道就是一个消息队列。
    # 发布者:import redis
    conn = redis.Redis(host='127.0.0.1',port=6379)
    conn.publish('104.9MH', "hahahahahaha")# 订阅者:import redis
    conn = redis.Redis(host='127.0.0.1',port=6379)
    pub = conn.pubsub()
    pub.subscribe('104.9MH')while True:
    msg= pub.parse_response()
    print(msg)
    对了,redis 做消息队列不合适,业务上避免过度复用一个redis,用它做缓存、做计算,还做任务队列,压力太大,不好。
    
    
  38. 如何基于redis实现发布和订阅?以及发布订阅和消息队列的区别?

    # 发布和订阅,只要有任务就所有订阅者每人一份。
    发布者: #发布一次
    import redis
    conn = redis.Redis(host='127.0.0.1',port=6379)
    conn.publish('104.9MH', "hahahahahaha")
    订阅者: #'while True'一直在接收
    import redis
    conn = redis.Redis(host='127.0.0.1',port=6379)
    pub = conn.pubsub()
    pub.subscribe('104.9MH')
    while True:
    msg= pub.parse_response()
    print(msg)
    
    
  39. 什么是codis及作用?

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

    Twemproxy 也叫 nutcraker。是 Twtter 开源的一个 Redis 和 Memcache 代理服务器,
    主要用于管理 Redis 和 Memcached 集群,减少与Cache 服务器直接连接的数量
    其功能:
    通过代理的方式减少缓存服务器的连接数。
    自动在多台缓存服务器间共享数据。
    通过不同的策略与散列函数支持一致性散列。
    通过配置的方式禁用失败的结点。
    运行在多个实例上,客户端可以连接到首个可用的代理服务器。
    支持请求的流式与批处理,因而能够降低来回的消耗。
    
    
  41. 写代码实现redis事务操作。

    使用MULTI命令便可以进入一个Redis事务。这个命令的返回值总是OK。此时,用户可以发出多个Redis命令。Redis会将这些命令放入队列,而不是执行这些命令。一旦调用EXEC命令,那么Redis就会执行事务中的所有命令。相反,调用DISCARD命令将会清除事务队列,然后退出事务。
    import redis
    pool = redis.ConnectionPool(host='10.211.55.4', port=6379)
    conn = redis.Redis(connection_pool=pool)# pipe = r.pipeline(transaction=False)
    pipe = conn.pipeline(transaction=True)# 开始事务pipe.multi()
    pipe.set('name', 'zgc')
    pipe.set('role', 'haha')
    pipe.lpush('roless', 'haha')# 提交pipe.execute()'注意':咨询是否当前分布式redis是否支持事务
    
    
  42. redis中的watch的命令的作用?

    watch 用于在进行事务操作的最后一步也就是在执行exec 之前对某个key进行监视
    如果这个被监视的key被改动,那么事务就被取消,否则事务正常执行.
    一般在MULTI 命令前就用watch命令对某个key进行监控.如果想让key取消被监控,可以用unwatch命令
    
    
  43. 基于redis如何实现商城商品数量计数器?

    指定键的值做加加操作,返回加后的结果。
    '通过redis的watch实现'import redis
    conn = redis.Redis(host='127.0.0.1',port=6379)# conn.set('count',1000)
    val = conn.get('count')print(val)
    with conn.pipeline(transaction=True) as pipe:
    # 先监视,自己的值没有被修改过
    conn.watch('count')
    # 事务开始 pipe.multi()
    old_count = conn.get('count')
    count = int(old_count)
    print('现在剩余的商品有:%s',count)
    input("问媳妇让不让买?")
    pipe.set('count', count - 1)
    # 执行,把所有命令一次性推送过去 pipe.execute()
    数据库的锁
    
    
  44. 简述redis分布式锁和redlock的实现机制。

    在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段。 
    一个Client想要获得一个锁需要以下几个操作:
    得到本地时间Client使用相同的key和随机数,按照顺序在每个Master实例中尝试获得锁。在获得锁的过程中,为每一个锁操作设置一个快速失败时间(如果想要获得一个10秒的锁, 那么每一个锁操作的失败时间设为5-50ms)。这样可以避免客户端与一个已经故障的Master通信占用太长时间,通过快速失败的方式尽快的与集群中的,其他节点完成锁操作。客户端计算出与master获得锁操作过程中消耗的时间,当且仅当Client获得锁消耗的时间小于锁的存活时间,
    并且在一半以上的master节点中获得锁。才认为client成功的获得了锁。
    如果已经获得了锁,Client执行任务的时间窗口是锁的存活时间减去获得锁消耗的时间。 
    如果Client获得锁的数量不足一半以上,或获得锁的时间超时,那么认为获得锁失败。
    客户端需要尝试在所有的master节点中释放锁, 即使在第二步中没有成功获得该Master节点中的锁,
    仍要进行释放操作。
    # redis分布式锁?
    # 不是单机操作,又多了一/多台机器
    # redis内部是单进程、单线程,是数据安全的(只有自己的线程在操作数据)
    ----------------------------------------------------------------#A、B、C,三个实例(主)
    1、来了一个'隔壁老王'要操作,且不想让别人操作,so,加锁;
    加锁:'隔壁老王'自己生成一个随机字符串,设置到A、B、C里(xxx=666)2、来了一个'邻居老李'要操作A、B、C,一读发现里面有字符串,擦,被加锁了,不能操作了,等着吧~
    3、'隔壁老王'解决完问题,不用锁了,把A、B、C里的key:'xxx'删掉;完成解锁4、'邻居老李'现在可以访问,可以加锁了# 问题:
    1、如果'隔壁老王'加锁后突然挂了,就没人解锁,就死锁了,其他人干看着没法用咋办?2、如果'隔壁老王'去给A、B、C加锁的过程中,刚加到A,'邻居老李'就去操作C了,加锁成功or失败?3、如果'隔壁老王'去给A、B、C加锁时,C突然挂了,这次加锁是成功还是失败?4、如果'隔壁老王'去给A、B、C加锁时,超时时间为5秒,加一个锁耗时3秒,此次加锁能成功吗?# 解决
    1、安全起见,让'隔壁老王'加锁时设置超时时间,超时的话就会自动解锁(删除key:'xxx')2、加锁程度达到(1/2)+1个就表示加锁成功,即使没有给全部实例加锁;3、加锁程度达到(1/2)+1个就表示加锁成功,即使没有给全部实例加锁;4、不能成功,锁还没加完就过期,没有意义了,应该合理设置过期时间# 注意
    使用需要安装redlock-py----------------------------------------------------------------from redlock import Redlock
    dlm = Redlock(
    [
    {"host": "localhost", "port": 6379, "db": 0},
    {"host": "localhost", "port": 6379, "db": 0},
    {"host": "localhost", "port": 6379, "db": 0},
    ]
    )# 加锁,acquire
    my_lock = dlm.lock("my_resource_name",10000)if my_lock:
    # 进行操作
    # 解锁,release dlm.unlock(my_lock)else:
    print('获取锁失败')#通过sever.eval(self.unlock_script)执行一个lua脚本,用来删除加锁时的key
    
    
  45. 什么是一致性哈希?Python中是否有相应模块?

    # 一致性哈希一致性hash算法(DHT)可以通过减少影响范围的方式,解决增减服务器导致的数    
    据散列问题,从而解决了分布式环境下负载均衡问题;
    如果存在热点数据,可以通过增添节点的方式,对热点区间进行划分,将压力分配至其他服务器,    重新达到负载均衡的状态。# 模块:hash_ring
    
  46. 如何高效的找到redis中所有以oldboy开头的key?

    redis 有一个keys命令。
    # 语法:KEYS pattern
    # 说明:返回与指定模式相匹配的所用的keys。该命令所支持的匹配模式如下:1、?:用于匹配单个字符。例如,h?llo可以匹配hello、hallo和hxllo等;2、*:用于匹配零个或者多个    
    字符。例如,h*llo可以匹配hllo和heeeello等;2、[]:可以用来指定模式的选择区间。例如h[ae]llo可以匹配hello和hallo,但是不能匹配hillo。同时,可以使用“/”符号来转义特殊的字符# 注意KEYS 的速度非常快,但如果数据太大,内存可能会崩掉,
    如果需要从一个数据集中查找特定的key,最好还是用Redis的集合结构(set)来代替。
    

47、悲观锁和乐观锁的区别?

# 悲观锁 从数据开始更改时就将数据锁住,直到更改完成才释放;会造成访问数据库时间较长,并发性不好,特别是长事务。# 乐观锁 直到修改完成,准备提交修改到数据库时才会锁住数据,完成更改后释放;相对悲观锁,在现实中使用较多。

posted @ 2019-06-24 18:49  搞事^o^Boy  阅读(113)  评论(0)    收藏  举报