c++面试基础篇(一)数据与通讯

数据

MySql(持久化数据库)

三范式

可参考博客:
https://www.cnblogs.com/JTrun/p/11069652.html
https://blog.csdn.net/dimei8552/article/details/101346531
简单记忆:
1NF:属性具有原子性
2NF:1NF+非码属性必须完全依赖于候选码(消除部分依赖)
3NF:2NF+非主属性不依赖于其他非主属性(消除传递依赖)

mysql架构

【基础架构】
每个学mysql的都必须知道它的基础架构,无非是连接器、分析器、优化器、执行器之类的东西。
看这篇,写得相当好:https://blog.csdn.net/qq_23864697/article/details/108155455

摘抄重点如下:

MySQL 可以分为 Server 层和存储引擎层两部分。
Server层:连接器、查询缓存、分析器、优化器、执行器等,所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。
存储引擎层:插件式的架构,支持 InnoDB、MyISAM、Memory 等多个存储引擎,负责数据的存储和提取
———————————————— 版权声明:本文为CSDN博主「凯凯王的技术生涯」的原创文章,遵循CC 4.0
BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_23864697/article/details/108155455

另外提一句:
自从MySQL 5.6(2013)以来,查询缓存已被禁用。
MySQL 8.0不再支持查询缓存,用户升级将被鼓励使用服务器端查询重写或ProxySQL作为中间缓存。
详见:https://blog.csdn.net/weixin_42389113/article/details/113205869

【Innodb】
mysql 支持多个存储引擎,曾经是 myisam,因为它不支持事务,已经被淘汰了(没人用了)。
现在都用mysql默认的数据库引擎Innodb,它支持事务。现在我们说 mysql 基本就是在说 基于 Innodb 的 MySql。

我将从两方面切入解析

  1. change buffer、redolog、undolog、binlog等数据结构和文件,这些被用于各种运行、容错、持久化机制。
  2. 并发事务及其带来的问题(脏读、不可重复读、幻读)和解决方式(隔离级别、锁);

从 数据结构/文件 切入

【change buffer(写缓存)】
形象的详见:https://zhuanlan.zhihu.com/p/158879979

重点摘抄: redo log 主要节省的是随机写磁盘的 IO 消耗(转成顺序写),而 change buffer
主要节省的是随机读磁盘的IO消耗

它写得很好,我如果讲解反而画蛇添足了,一定要进去看看。

下面这个讲得更为具体精确:https://blog.csdn.net/u010900754/article/details/106744734

对于一次更新操作,innodb引擎会看更新的页是否在buffer pool中,如果在,那么直接更新buffer pool,并且写入一条redo log。这样后续的读取操作可以读到最新的值。如果不在,那么就先将本次更新操作记录到change buffer中,而不是立刻更新,最后再记录一条redo log。如果后面有读操作,那么再将对应的数据页载入到buffer pool中,同时将change pool中的更新操作应用到该数据页,这个过程叫做merge。当然如果系统是空闲状态,也会有后台线程去做merge过程。

可以看到,innodb对于更新操作的优化原则就是使用缓存手段,尽量延后更新操作。当然这个思路仅适用于写多读少的场景,比如日志系统。因为如果写完数据后立刻要读,那么没有必要额外维护change buffer的缓存了

还有一点,change buffer仅用于更新普通索引,对唯一性索引无效,因为唯一性索引肯定要读数据页做唯一性判断的。
———————————————— 版权声明:本文为CSDN博主「绝世好阿狸」的原创文章,遵循CC 4.0
BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u010900754/article/details/106744734

我解释一下最后这句

change buffer仅用于更新普通索引,对唯一性索引无效,因为唯一性索引肯定要读数据页做唯一性判断的。

  1. change buffer对于更新(插入删除更新)普通索引有加速作用,原理在于尽量延后更新操作(下次读的时候再更新,尽量延后、减少读磁盘的操作),仅适用于写多读少的场景
  2. 而唯一性索引(包括主键索引)在更新时需要做唯一性判断,也就是判断此次更新是否会破坏这一属性列的唯一性,在实现上肯定不能省去读磁盘的操作,该读多少就读多少,也就起不到延后读磁盘的目的了。

【WAL技术】
WAL技术, WAL 的全称是 Write-Ahead Logging ,它的关键点就是先写日志,再写磁盘,保证持久化到磁盘。
虽然我们更新数据时只更新内存的change buffer,但是在事务提交的时候,我们把 change buffer 的操作也记录到 redolog 里了,所以崩溃恢复的时候, changebuffer 也能找回来。这就是redolog在崩溃恢复中的作用。

【redolog、undolog、binlog】
看这几篇了解下:
https://blog.csdn.net/mx_1995/article/details/101051103
https://www.cnblogs.com/f-ck-need-u/p/9010872.html
https://www.bilibili.com/read/cv8405294/
https://www.bbsmax.com/A/kvJ3yPPXdg/
https://www.cnblogs.com/wwyydd/p/14120410.html
超详细https://www.cnblogs.com/f-ck-need-u/p/9010872.html
【注:以下内容多有摘抄自上面链接】

内容很多,但最终要记住几个东西:
1、层次不同

undolog、redolog 是 InnoDB 引擎特有的,用以来支持事务;
——————————————————————————
再重复一遍: undolog、redolog专门用来支持事务:
在事务开启过程中的更新操作会记录到undolog上。
在事务提交的时候,我们把 change buffer 的操作也记录到 redolog 里(在崩溃恢复时,changebuffer 也能通过 redolog 找回来)。
可以看看:https://www.bbsmax.com/A/kvJ3yPPXdg/

binlog 是 MySQL 的 Server 层实现的日志,所有的引擎都有。对于事务的修改,binlog只会在事务提交后进行记录。

2、记录形式

redolog 是物理日志,记录的是"在 XXX 页上做了 XXX 修改",记录修改后的值

binlog 是逻辑日志,比如" 给 id = 2 这一行的 c 字段加 1",记录的是这个更新语句的原始逻辑

undolog 也是逻辑日志,记录相反的执行语句。
“undo就是rollback txn id,然后根据txn id找到需要rollback的相关记录。只要你有一个关联集就可以做undo。”——https://www.zhihu.com/question/456702311/answer/1856193222

3、文件属性

redolog 是有固定大小的,所以它的空间会用完,如果用完的话,一定要进行一些写入磁盘的操作才可以继续。可以看成环形空间, 两个指针(或者偏移量)write pos 和 checkpoint ,writepos会移动,移动到checkpoint也就是空间用完,那么就会前移checkpoint,写入磁盘、腾出空间——脑子里要有这样的模型。

binlog 是可以追加写入的,也就是 binlog 没有空间的概念,一直写就行了

换句话说——“binlog日志不会循环使用,当binlog 写满时,会另写一个binlog文件;而redolog 文件是循环使用的”。

4、作用不同

undolog 日志是Mysql用来实现事务原子性的,事务在执行的过程中,操作任何数据之前先将数据备份到undolog中,事务失败时可根据undolog进行回滚。.
在InnoDB引擎中,undolog还可以用来实现多版本并发控制MVCC。

redolog记录已成功提交事务的修改信息,并且会把redolog持久化到磁盘,系统重启之后(正常重启或崩溃后重启)读取redolog恢复最新数据。
redo log是用来恢复数据的,用于保障已提交事务的持久化特性。

binlog 适合用来备份, 主从复制就是根据binlog 来实现数据同步的

【两阶段提交,以及状态的恢复与更新】

两阶段提交的过程:

redolog 在事务执行的过程中不断记录事务操作的变化。
"两阶段提交"就是:

  1. 先写redolog,并置redolog为prepare状态
  2. 再写binlog ,等 binlog 写完之后,redolog才是 commit 状态

以此来保证binlog与redolog 的一致性。

具体解释【binlog与redolog 的一致性】:

redo log 和 binlog 都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致。
可以假设一下,如果不采用这种方式,而是就先写 redo log ,再写 binlog ,会怎样?如果在写 binlog 时,发生了异常,更新操作已经到 redo log 中了,但是此时 binlog 并没有进行更新,是不是出现了数据不一致?
先写 binlog 再写 redo log 也是一样的道理。
所以,在写时,先让 redo log 处于 prepare 状态,等 binlog 写完之后,再让 redo log 处于 commit 状态,这样就保持了逻辑上的一致。

状态的恢复与更新

若在事务过程中发生系统故障时,数据库会根据redolog 日志状态(prepare状态)恢复到事务前的状态
若事务已成功提交但数据未更新,数据库会根据redolog 日志(此时为commited状态)更新到事务完成后的状态。

b+树

简单记住这句话:
b+树就是专门用来减少检索过程中的磁盘IO次数的。
Innodb使用b+树来实现索引。
Innodb不支持hash索引。

为什么要使用b+树来实现数据库的索引,而不使用二叉树、红黑树、b-树、hash呢?

  1. 从减少磁盘IO的角度来说(最主要的原因)

首先要有一个大致的了解:

表空间可看做是InnoDB存储引擎逻辑结构的最高层。 表空间文件:InnoDB默认的表空间文件为ibdata1。
段:表空间由各个段组成,常见的段有数据段、索引段、回滚段(undo log段)等。
区:由64个连续的页组成,每个页大小为16kb,即每个区大小为1MB。
页:每页16kb,且不能更改。常见的页类型有:数据页、Undo页、系统页、事务数据页、插入缓冲位图页、插入缓冲空闲列表页、未压缩的二进制大对象页、压缩的二进制大对象页。
——https://www.bbsmax.com/A/kvJ3yPPXdg/。

首先,mysql数据是存在于磁盘而不是内存的,使用时需要把数据从磁盘调到内存里,这就叫磁盘IO。

假设我们索引树的一个结点就对应物理数据的一页(Innodb一页默认16kb),或者说一次磁盘IO(一次磁盘IO至少拿一页)。

磁盘IO的花销太大,所以我们需要的索引结构是让我们减少磁盘IO的次数 == 利用索引磁盘调到内存的页(或者说树的结点)越少越好 == 减少检索的次数 == 要求索引树的 层数最少 or 高度最低。
使用二叉树(红黑树也是二叉树)是不行的,因为二叉树相同数据量情况下,层数肯定大于多叉树。
b树和b+树都是多叉树,叉数都可以自己定,唯一的区别在于b+树的数据都存在叶子节点,索引放非叶子结点;而b树的数据存在所有节点。
索引的数据量则相对小(只有索引列)。
如果是主键索引,一条数据就是一个数据行,一个数据行可能有几十列属性,数据量很大!(辅助索引虽然放的是)
如果是辅助索引,数据就是主键而已。
总之,如果统一为在非叶子结点上全放索引,这样层数才能少,也更合理。
b+树就是 数据全放叶子结点上、索引放非叶子结点 的数据结构,所以b+树层数一般比b树还要少,更适合用来做数据库的索引。

  1. 从有序遍历、范围遍历的角度来说
  • 用树可以实现有序的结构、有序地遍历,可以有一个范围,而hash不行。
  • b+树的有序遍历最简单,它的数据都在叶子节点,且叶子节点相当于双向链表,可以直接遍历;b+树依靠自己的结构还可以实现间隙锁等操作。
  • 红黑树的有序遍历、范围遍历需要中序遍历,不像b+树那么方便
  • b-树等的有序遍历、范围遍历同样不比b+树方便。

从 并发事务 切入

注意:事务的开始不是begin,而是对数据进行了增删改查等操作后才开启了一个事务。

1、并发事务带来的问题
并发事务会带来脏读、不可重复读、幻读等问题,要解决这些问题,需要先了解事务隔离级别。

2、五种隔离级别

TRANSACTION_NONE,不使用事务就不会有问题
读未提交(ReadCommitted,简称RC),不解决问题
读已提交(ReadUncommitted,简称RU),解决脏读问题
可重复读(ReadRepeat,简称RR),解决不可重复读问题,可以通过一些措施在这个隔离机制下解决幻读问题。
串行化(Serializable,很少人称简称),使用【两阶段缩协议】,解决幻读等所有并发事务带来的问题

查看mysql隔离事务,默认是可重复读

show variables like ‘transaction_isolation’;

要采取哪种级别你可以在mysql里设置。
一般没人会用【串行化】,性能影响太大了!
也很少人会用【读未提交】,除非他不关心这些问题(确实可能有这种情况)。
MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读);

【加锁 - 读已提交的实现方式】
读已提交就是靠加锁实现的,锁的类型在下面有讲。

【快照 - 可重复读的实现方式】
mysql 中,可重复读是用快照(snapshot)实现多版本并发控制(MVCC)的。快照的好处是读写不冲突,有利于提高并发度。mysql中的快照(snapshot)实现的是伪 MVCC

简单理解就是:事务A和事务B同时运行的时候,事务A读取某条数据行是按照版本读的,就是事务A开启时有已经有定下一个版本了。
但 mysql 快照要重点掌握,我们要了解具体是怎么实现的。

【Read-View视图】
RU(Read Committed,读未提交)隔离级别下直接返回记录上的最新值,没有视图概念。
在RU 隔离级别下,start transaction withconsistent snapshot就没意义了,等效于普通的 start

为实现支持RC ( Read Committed ,读已提交)和 RR ( Repeatable Read ,可重复读),数据库里面会创建一个 “一致性读视图”(consistent read view),访问的时候以视图的逻辑结果为准,作用是事务执行期间用来定义 “ 我能看到什么数据 ”

  • 在 RC 隔离级别下,这个视图是在每个 SQL 语句开始执行的时候创建的。
  • 在 RR 隔离级别下,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图。就像 “ 拍了个快照 ” ,所以此时的一致性读又称为快照读
  • 在 RR 隔离级别下,如果你想要马上启动一个事务,可以使用 start transaction withconsistent snapshot 这个命令,创建一个持续整个事务的一致性快照

“ 串行化 ” 隔离级别下直接用加锁的方式来避免并行访问。

所以,事务启动时的视图可以认为是静态的,不受其他事务更新的影响。

注:start transaction == begin,它们两个没有区别。
——https://blog.csdn.net/qq_32617703/article/details/103601271

【MVCC】
每条记录在更新的时候都会同时在 undolog 记录一条回滚操作。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。不同时刻启动的事务会有不同的 read-view 视图,那么同一条记录在系统中可以存在多个版本,就是数据库的多版本并发控制( MVCC )。
在在 “ 可重复读 ” 隔离级别下,这个read-view视图是在事务启动时创建的,且是基于整库的,然而,我们启动事务的时候并不需要拷贝整个库的内容。
要了解 transaction id 和 row trx_id

  • InnoDB 里面每个事务有一个唯一的事务 ID ,叫作 transaction id 。它是在事务开始的时候向InnoDB
    的事务系统申请的,是按申请顺序严格递增的。
  • 而每行数据也都是有多个版本的。每次事务更新数据的时候,都会生成一个新的数据版本,并且把 transaction id
    赋值给这个数据版本的事务 ID ,记为 row trx_id 。
    也就是说,数据表中的一行记录,其实可能有多个版本 (row)
    ,每个版本有自己的 row trx_id 。

数组里面事务 ID 的最小值记为低水位,当前系统里面已经创建过的事务 ID 的最大值加 1 记为高水位。这个视图数组和高水位,就组成了当前事务的一致性视图( read-view )。而数据版本的可见性规则,就是基于数据的 row trx_id 和这个一致性视图的对比结果得到的,即对比数据版本的row trx_id和事务的id数组

【脏读、不可重复读、幻读】
直接看这个吧,定义写得不错:
https://blog.csdn.net/xiaolinyouni/article/details/6997392
它这个的解决问题说的不是mysql的,mysql里面解决不可重复读问题不是加锁,而是快照读。

【不可重复读与幻读的区别】

  1. 搬运自:https://blog.csdn.net/jdnicky/article/details/91493719
    不可重复读的重点是修改:
    同样的条件, 你读取过的数据, 再次读取出来发现值不一样了
    幻读的重点在于新增或者删除:
    同样的条件, 第1次和第2次读出来的记录数不一样
    当然, 从总的结果来看, 似乎两者都表现为两次读取的结果不一致.
    但如果你从控制的角度来看, 两者的区别就比较大
    对于前者, 只需要锁住满足条件的记录
    对于后者, 要锁住满足条件及其相近的记录
  2. 搬运自:https://www.zhihu.com/question/392569386
    其实很好区分:**不可重复读是读异常,但幻读则是写异常。**不可重复读是读异常的意思是,如果你不多select几次,你是发现不了你曾经select过的数据行已经被其他人update过了。避免不可重复读主要靠一致性快照。幻读是写异常的意思是,如果不自己insert一下,你是发现不了其他人已经偷偷insert过相同的数据了。解决幻读主要靠间隙锁。 没有第四条。

【解决幻读问题】

可重复读的隔离级别没有办法彻底的解决幻读的问题,如果我们的项目中需要解决幻读的话也有两个办法: 1、使用串行化读的隔离级别
2、MVCC+Next-Key Lock(临键锁)。
默认情况下,InnoDB工作在 RR 隔离级别下,会以Next-Key Lock的方式对数据行进行加锁,这样可以有效防止幻读的发生。
实际上很多的项目中是不会使用到上面的两种方法的,串行化读的性能太差,而且其实幻读很多时候是我们完全可以接受的。【这句话是引用自上面链接的,我也不知道是不是这样】

【间隙锁、临键锁】

产生幻读的原因是,行锁只能锁住行,但是新插入记录这个动作,要更新的是记录之间的 “ 间隙 ” 。 为了解决幻读问题, InnoDB
只好引入新的锁,也就是间隙锁 (GapLock) 。对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”。
锁的就是两个值之间的空隙。在一行行扫描的过程中,不仅将给行加上了行锁,还给行两边的空隙,也加上了间隙锁。 间隙锁和行锁合称 Next-Key Lock(临键锁)。
每个 next-key lock 是前开后闭区间。即包含了记录锁和间隙锁,即锁定一个范围,并且锁定记录本身。

【快照读和当前读】
参考:
https://blog.csdn.net/cug_jiang126com/article/details/50544728
这个有点出错(MySql的RR隔离级别下确实能完全解决幻读问题了),但写得很好:https://blog.csdn.net/qq_42914528/article/details/103790555

【快照读(非阻塞读)–伪MVCC】
为什么是伪MVCC
MVCC就是多版本并发控制,也就是非阻塞读,上面提到的MVCC为什么是伪MVCC呢?因为这里的undolog是串行化的,不属于多个版本共存的例子,所以不是MVCC。undolog是逻辑日志,使用对当前数据执行undo命令的方式来获取“旧版本”的数据。

【快照读】

不加锁的非阻塞读,即select操作
当执行select操作是innodb默认会执行快照读,会记录下这次select后的结果,之后select
的时候就会返回这次快照的数据,即使其他事务提交了不会影响当前select的数据,这就实现了可重复读了。
快照的生成当在第一次执行select的时候,也就是说假设当A开启了事务,然后没有执行任何操作,这时候B
insert了一条数据然后commit,这时候A执行 select,那么返回的数据中就会有B添加的那条数据。
之后无论再有其他事务commit都没有关系,因为快照已经生成了,后面的select都是根据快照来的。

不过这里的快照读是基于非Serializable事务隔离界别下的,因为在Serializable隔离级别下,快照度会退化为当前读。

【当前读】
对于会对数据修改的操作(update、insert、delete)都是采用当前读的模式。在执行这几个操作时会读取最新的记录,即使是别的事务提交的数据也可以查询到。
select的当前读需要手动的加锁
select * from table where ? lock in share mode;
select * from table where ? for update;

SELECT … LOCK IN SHARE
MODE走的是IS锁(意向共享锁),即在符合条件的rows上都加了共享锁,这样的话,其他session可以读取这些记录,也可以继续添加IS锁,但是无法修改这些记录直到你这个加锁的session执行完成(否则直接锁等待超时)。

SELECT … FOR UPDATE
走的是IX锁(意向排它锁),即在符合条件的rows上都加了排它锁,其他session也就无法在这些记录上添加任何的S锁或X锁。如果不存在一致性非锁定读的话,那么其他session是无法读取和修改这些记录的,但是innodb有非锁定读(快照读并不需要加锁),for
update之后并不会阻塞其他session的快照读取操作,除了select …lock in share mode和select
… for update这种显示加锁的查询操作。

通过对比,发现for update的加锁方式无非是比lock in share mode的方式多阻塞了select…lock in
share mode的查询方式,并不会阻塞快照读。 ————————————————
版权声明:本文为CSDN博主「胡儿胡儿」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/cug_jiang126com/article/details/50544728

【两阶段锁协议 - 串行化的实现方式】

开始阶段只加锁,结束阶段只解锁。
两阶段锁定真正实现了串行化性质,它可以防止之前讨论的所有并发问题,也是性能损耗最大的选择,尤其是它可能会更频繁地导致死锁出现。事务由于死锁而被中止后只能重试,这意味着巨大的开销。
要区别 【两阶段锁协议】 和 【两阶段提交】,这两个东西没有任何关系。

3、MySql 的锁
可参考:https://blog.csdn.net/sayoko06/article/details/89945410

全局锁【全库逻辑备份用、官方逻辑备份工具是mysqldump】

表锁(table lock) :表读锁(Table Read Lock)和表写锁(Table Write Lock) 、MDL 元数据锁

下面我需要再看看
// https://blog.csdn.net/caox_nazi/article/details/83817746
// https://blog.csdn.net/hanpeiyu1995/article/details/90180385

出现 这个状态表示的是,现在有一个线程正在表 t 上请求或者持有 MDL 写锁,把 select 语句堵住了。例如:session A 通过 lock table 命令持有表 t 的 MDL 写锁,而 session B 的查询需要获取 MDL 读锁。所以, session B 进入等待状态。
这类问题的处理方式,就是找到谁持有 MDL 写锁,然后把它 kill 掉。
通过查询 sys.schema_table_lock_waits 这张表,我们就可以直接找出造成阻塞的 process id ,把这个连接用 kill 命令断开即可。

行锁(recode lock):共享锁 (用法:select * from table where xxx lock in share model) 和 排他锁(用法:select * from table where xxx for update)

  • recode lock 存在于包括主键索引在内的唯一索引中,锁定单条索引记录。
  • InnoDB 中的 recode lock 的实现依赖于索引,一旦某个加锁操作没有使用到索引,那么该锁就会退化为表锁。

间隙锁(gap lock) :间隙锁存在于非唯一索引中,锁定开区间范围内的一段间隔。

临键锁(next-key lock)= recode lock + gap lock
临键锁存在于非唯一索引中,该类型的每条记录的索引上都存在这种锁,它是一种特殊的间隙锁,锁定一段左开右闭的索引区间。
https://www.cnblogs.com/crazylqy/p/7821481.html
InnoDB 中行级锁是基于索引实现的,临键锁只与非唯一索引列有关,在唯一索引列(包括主键列)上不存在临键锁。

MySql高可用

【读写分离】
搞一个从数据库专门用来读,主数据库专门用来写(这两个数据库一般在两台机子上)

【缓存】
在数据库上套一层redis缓存,需要做好缓存和数据库的同步数据更新操作

【集群】
堆机器罢了

锁:悲观锁、乐观锁

悲观锁一般就是 for update,
乐观锁可以用版本号、CAS来做

MySql C++的使用

*NOSQL相关持久化的数据库了解不多,有空再说 *

Redis(缓存)

Redis基础与实践

【五种数据结构】:
string,hash,list,set,zset
讲这些太无聊,直接看菜鸟教程:https://www.runoob.com/redis/redis-tutorial.html

linux上配置与使用 以及 持久化可以看我这篇:
https://blog.csdn.net/xmz782429852/article/details/119774494

Redis底层

压缩链表、跳表之类的
之后再讲

hiredis

看看这三篇差不多了:
https://www.jianshu.com/p/788e8b44f225
https://www.jianshu.com/p/cafb80392fbb
https://www.cnblogs.com/jabnih/p/4814212.html
下面这个是我随手写的测试文件,用这个玩玩就大概能了解hiredis了,hiredis也就这样了,和 redis-cli 没多大区别,要怎么用自己去封装。

#include 
#include 
#include 

// 点进去看看函数,了解一下是什么文件
//#include 
//#include 
//#include 
//#include 
//#include 

int main(int argc, char* argv[]) {
    // 建立redis连接
    redisContext* c = redisConnect("你的ip地址", 6379);// redis-server默认绑定端口是 6379
    if (c != NULL && c->err) {
        printf("Error: %sn", c->errstr);
        // handle error 
        return 1;
    }
    else std::cout << "与redis服务端建立连接" << std::endl;

    redisReply *reply;
    reply = static_cast<redisReply*>(redisCommand(c, "AUTH 123456"));// 你在服务端设置的密码

    std::string s;
    while (getline(std::cin,s)) {
        if (s == "exit")break;
        redisReply* reply = static_cast<redisReply*>(redisCommand(c, s.c_str()));
        std::cout << "reply->type =" << reply->type << std::endl;
        std::cout << "reply->str =" << reply->str << std::endl;
        std::cout << "reply->integer =" << reply->integer << std::endl;
        std::cout << "reply->dval =" << reply->dval << std::endl;
        std::cout << "reply->element =" << reply->element << std::endl;
        std::cout << "reply->elements =" << reply->elements << std::endl;
        std::cout << "reply->len =" << reply->len << std::endl << std::endl;
    }
    freeReplyObject(reply);
    redisFree(c);
    std::cout << "主动断开连接" << std::endl;

    //redisReply* reply = static_cast(redisCommand(c, "set meson me"));
    //std::cout << "reply->integer =" << reply->integer << std::endl;
    //std::cout << "reply->str =" << reply->str << std::endl;
    //std::cout << "reply->type =" << reply->type << std::endl;
    //std::cout << "reply->dval =" << reply->dval << std::endl;
}

Redis用法

消息队列
缓存队列
定时器
排行榜
记录点赞数

布隆过滤器

其实看这篇就可以懂原理了
https://www.bilibili.com/video/BV1eU4y1J7GY

就是找不到(hash查找的位不全为1)就一定不存在,找得到可能不存在,即存在误判可能。

【redis 的布隆过滤器实践我之后再做】

Redis高可用

缓存穿透、缓存击穿、缓存雪崩
直接看这篇:
https://blog.csdn.net/kongtiao5/article/details/82771694
解决方案:
1-布隆过滤器
2-数据缓存过期时间设置随热度不同而不同
3-热点数据的过期时间会更长

读多写少
读多写少,读写分离,多级缓存,然后用消息队列比如 kafka 来实现数据一致性。
https://www.bilibili.com/video/BV1Lq4y1975x

集群
Redis集群没人用哨兵,选举、切换时间较长大概几十秒十几秒。
Redis集群都用RedisCluster,切换时间大概一两秒。

通讯

IPC

IPC,进程间通信。要记住种类:管道(匿名管道/半双工管道、有名管道)、共享内存+信号量(不要用)、信号、socket、消息队列(一般没人用了,都用kafka/ZeroMQ/rocketMQ等中间件)
其实看这几篇就够了
https://zhuanlan.zhihu.com/p/165224175
https://blog.csdn.net/centor/article/details/76736601

着重掌握管道(pipe/mkfifo)、socket、
对于不使用的管道读写段需要关闭:https://blog.csdn.net/qq_39781096/article/details/104078742

Actor模型和CSP模型

消息队列

Kafka/ZeroMQ/RabbitMQ/RocketMQ
消息队列的作用

协议

protobuff

rpc

grpc

分布式

CAP :在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。

CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。

更新日志

2021.8.8:更新大纲,待补
2021.8.10:添加MySql内容,待补
2021.8.24:添加redis内容,待补

你可能感兴趣的:(面经,数据库,redis,缓存)