平衡树(Balance Tree,BT) 指的是,任意节点的子树的高度差都小于等于1。常见的符合平衡树的有,B树(多路平衡搜索树)、AVL树(二叉平衡搜索树)等。
二叉搜索树的特点:对于树中的每个节点X,它的左子树中所有关键字值小于X的关键字值,而它的右子树中所有关键字值大于X的关键字值。
排序方法 | 时间复杂度(平均) | 时间复杂度(最坏) | 时间复杂度(最好) | 空间复杂度 | 稳定性 | 复杂性 |
---|---|---|---|---|---|---|
插入排序 | O(n2) | O(n2) | O(n) | O(1) | 稳定 | 简单 |
希尔排序 | O(nlog2n) | O(n2) | O(n1.3) | O(1) | 不稳定 | 较复杂 |
选择排序 | O(n2) | O(n2) | O(n2) | O(1) | 不稳定 | 简单 |
堆排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | O(1) | 不稳定 | 较复杂 |
冒泡排序 | O(n2) | O(n2) | O(n) | O(1) | 稳定 | 简单 |
快速排序 | O(nlog2n) | O(n2) | O(nlog2n) | O(nlog2n) | 不稳定 | 较复杂 |
归并排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | O(n) | 稳定 | 较复杂 |
基数排序 | O(d(n+r)) | O(d(n+r)) | O(d(n+r)) | O(n+r) | 稳定 | 较复杂 |
参考博客https://www.cnblogs.com/zwtgyh/p/10631760.html
AVL树本质上是一颗二叉查找树,但是它又具有以下特点:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为平衡二叉树。
红黑树的性质如下:
区别:
https://codemouse.online/archives/2020-06-30202243
http的全称是Hypertext Transfer Protocol Vertion (超文本传输协议),说通俗点就是用网络链接传输文本信息的协议。
http协议的缺点:
通信使用明文,内容可能被窃听(重要密码泄露)
不验证通信方身份,有可能遭遇伪装(跨站点请求伪造)
无法证明报文的完整性,有可能已遭篡改(运营商劫持)
https就是再http的基础上套了一层ssl/tls的加密壳。
通过非对称加密传输密钥+对称加密传输数据+证书的方式。
https://www.cnblogs.com/kubidemanong/p/9390021.html
事务四大特征:
原子性( Atomicity, 或称不可分割性) 、
一致性( Consistency) 、
隔离性( Isolation, 又称独立性) 、
持久性( Durability) 。
使用系统变量设置事务隔离级别
SET GLOBAL tx_isolation=‘REPEATABLE-READ’; #全局
SET SESSION tx_isolation=‘REPEATABLE-READ’; #局部
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(READ-UNCOMMITTED) | 是 | 是 | 是 |
不可重复读(READ-COMMITTED) | 否 | 是 | 是 |
可重复读(REPEATABLE-READ) | 否 | 否 | 是 |
串行化(SERIALIZABLE) | 否 | 否 | 否 |
并发事务问题
1.可以交给应用解决
更新丢失(Lost Update)
2.需要数据库提供事务间的隔离机制来解决
3.实现隔离机制的方法主要有两种
按照锁的粒度把数据库锁分为行级锁(INNODB引擎)、 表级锁(MYISAM引擎)和页级锁(BDB引擎 )。
行级锁
:行级锁是Mysql中锁定粒度最细的一种锁, 表示只针对当前操作的行进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小, 但加锁的开销也最大。 行级锁分为共享锁 和 排他锁。
特点: 开销大, 加锁慢; 会出现死锁; 锁定粒度最小, 发生锁冲突的概率最低, 并发度也最高。
表级锁
:表级锁是MySQL中锁定粒度最大的一种锁, 表示对当前操作的整张表加锁, 它实现简单, 资源消耗较少, 被大部分MySQL引擎支持。 最常使用的MYISAM与INNODB都支持表级锁定。 表级锁定分为表共享读锁( 共享锁) 与表独占写锁( 排他锁) 。
特点: 开销小, 加锁快; 不会出现死锁; 锁定粒度大, 发出锁冲突的概率最高, 并发度最低。
页级锁
:页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。 表级锁速度快, 但冲突多, 行级冲突少, 但速度慢。所以取了折衷的页级, 一次锁定相邻的一组记录。 BDB支持页级锁
特点: 开销和加锁时间界于表锁和行锁之间; 会出现死锁; 锁定粒度界于表锁和行锁之间, 并发度一般
MySQL的表锁有两种模式:
InnoDB两种类型的行锁:
InnoDB两种内部使用的意向锁( Intention Locks) , 这两种意向锁都是表锁。
根据存储分类
B-树索引
哈希索引
根据用途分类
普通索引,唯一性索引,主键索引,空间索引,全文索引
索引类型 | 特点 |
---|---|
普通索引 | 最基本的索引, 没有任何限制 |
唯一索引 | 与"普通索引"类似, 不同的就是: 索引列的值必须唯一, 但允许有空值。 |
主键索引 | 它是一种特殊的唯一索引, 不允许有空值。 |
全文索引 | 仅可用于 MyISAM 表, 针对较大的数据, 生成全文索引很耗时好空间。 |
组合索引 | 为了更多的提高 mysql 效率可建立组合索引, 遵循”最左前缀“原则。 创建复 合索引时应该将最常用(频率) 作限制条件的列放在最左边, 依次递减 |
索引的实现原理
MyISAM 引擎使用 B+Tree 作为索引结构,叶节点的 data 域存放的是数据记录的地址。
InnoDB 也使用 B+Tree 作为索引结构,InnoDB 的数据文件本身就是索引文件。
MyISAM 引擎使用 B+Tree 作为索引结构,叶节点的 data 域存放的是数据记录的地址。
InnoDB 也使用 B+Tree 作为索引结构,InnoDB 的数据文件本身就是索引文件。
https://blog.csdn.net/kyle_wu_/article/details/113287187
https://www.cnblogs.com/luchangyou/p/11321607.html
https://blog.csdn.net/whoamiyang/article/details/51901888?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control
聚簇索引首先并不是一种索引类型,而是一种数据存储方式,是否为聚簇索引实际上指的就是b+树的具体实现方式,也就是每个节点的data域里面到底放的是具体的数据,还是指向数据的地址。数据则是聚簇。
InnoDB存储引擎的主键使用的是聚簇索引,而非主键使用的称作:“辅助索引”、“二次索引”,而MqISAM存储引擎无论主键,还是非主键使用的索引都是一样的:“非聚簇索引”。
聚簇索引,被索引的列必须是主键列,如果没有主键,会选择一个唯一的非空索引代替,如果也没有这样的索引,那么会隐式定义一个主键来作为聚簇索引。因此,也可以说聚簇索引就是按照表的主键构造的一个b+树,同时叶子节点里面存储了表的行数据。
Redis支持五bai种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
集合(Set):
set集合存储一组不重复的数据,有两种实现方法:(1)有序数组实现,(2)散列表实现。
当存储的数据都是整数,并且存储的元素个数小于512个时,通过有序数组实现,否则通过散列表实现。
有序集合(SortSet):
Redis中的有序集合存储的是一组数据,并且每个数据都附带一个分数。有两种实现方式:(1)压缩列表,(2)跳表
zset的编码有ziplist(压缩链表)和skiplist(跳表)两种。
skiplist 编码的 Zset 底层为一个被称为 zset 的结构体,这个结构体中包含一个字典和一个跳跃表。跳跃表按 score 从小到大保存所有集合元素,查找时间复杂度为平均 O(logN),最坏 O(N) 。字典则保存着从 member 到 score 的映射,这样就可以用 O(1)的复杂度来查找 member 对应的 score 值。虽然同时使用两种结构,但它们会通过指针来共享相同元素的 member 和 score,因此不会浪费额外的内存。
typedef struct zset {
dict *dict;
zskiplist *zsl;
} zset;
https://www.cnblogs.com/ysocean/p/9080942.html
RDB持久化
AOF持久化
https://codemouse.online/archives/2021-01-26-23-22-45
LRU是最近最少使用页面置换算法(Least Recently Used),也就是首先淘汰最长时间未被使用的页面!
LFU是最近最不常用页面置换算法(Least Frequently Used),也就是淘汰一定时期内被访问次数最少的页!
进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。
线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是的)。
协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示调度。
进程和线程的区别:进程是资源的单位,线程是调度(CPU调度)执行的最小单位。
协程和线程的区别是:协程避免了无意义的调度,由此可以提高性能,但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力。
参考博客https://blog.csdn.net/weixin_40237626/article/details/82290475
分页和分段有许多相似之处,比如两者都不要求作业连续存放.但在概念上两者完全不同,主要表现在以下几个方面:
- 页是信息的物理单位,分页是为了实现非连续分配,以便解决内存碎片问题,或者说分页是由于系统管理的需要.段是信息的逻辑单位,它含有一组意义相对完整的信息,分段的目的是为了更好地实现共享,满足用户的需要.
- 页的大小固定,由系统确定,将逻辑地址划分为页号和页内地址是由机器硬件实现的.而段的长度却不固定,决定于用户所编写的程序,通常由编译程序在对源程序进行编译时根据信息的性质来划分.
- 分页的作业地址空间是一维的.分段的地址空间是二维的.
int pthread_create(pthread_t*restrict_tidp,const pthread_attr_t restrict_attr,void(start_rtn)(void),void *restrict_arg);
第一个参数为指向线程标识符的指针。
第二个参数用来设置线程属性。
第三个参数是线程运行函数的起始地址。
第四个参数是运行函数的参数。
Posix线程中的线程属性pthread_attr_t主要包括scope属性、detach属性、堆栈地址、堆栈大小、优先级。在pthread_create中,把第二个参数设置为NULL的话,将采用默认的属性配置。
临界区(Critical Section)、bai互斥du量(Mutex)、信号量(Semaphore)、事件(Event)的区别
1、临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。在任意时刻只允许一个线程对共享资源进行访问,如果有多个线程试图访问公共资源,那么在有一个线程进入后,其他试图访问公共资源的线程将被挂起,并一直等到进入临界区的线程离开,临界区在被释放后,其他线程才可以抢占。只能在本进程内使用。
2、互斥量:采用互斥对象机制。 只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问。互斥不仅能实现同一应用程序的公共资源安全共享,还能实现不同应用程序的公共资源安全共享。使用原子变量可以达到类似效果。
3、信号量:它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目
4、事 件: 通过通知操作的方式来保持线程的同步,还可以方便实现对多个线程的优先级比较的操作
1、无名管道通信
无名管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
2、高级管道通信
高级管道(popen):将另一个程序当做一个新的进程在当前程序进程中启动,则它算是当前程序的子进程,这种方式我们成为高级管道方式。
3、有名管道通信
有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
4、消息队列通信
消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
5、信号量通信
信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
6、信号
信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
7、共享内存通信
共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
8、套接字通信
套接字( socket ) : 套接口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。
当进程调用fork后,当控制转移到内核中的fork代码后,内核会做4件事情:
1、分配新的内存块和内核数据结构给子进程。
2、将父进程部分数据结构内容拷贝至子进程。
3、添加子进程到系统进程列表当中。
4、fork返回,开始调度器调度。
判断对方(设备,进程或其它网元)是否正常动行,一般采用定时发送简单的通讯包,如果在指定时间段内未收到对方响应,则判断对方已经当掉。用于检测TCP的异常断开。
基本原因是服务器端不能有效的判断客户端是否在线也就是说,服务器无法区分客户端是长时间在空闲,还是已经掉线的情况。所谓的心跳包就是客户端定时发送简单的信息给服务器端告诉它我还在而已。
代码就是每隔几分钟发送一个固定信息给服务端,服务端收到后回复一个固定信息。如果服务端几分钟内没有收到客户端信息则视客户端断开。比如有些通信软件长时间不使用,要想知道它的状 态是在线还是离线就需要心跳包,定时发包收包。
在 UDP 通讯中,当你的数据包发出去后,至于对方有没有正确收到数据,并不知道,那
么,如何保证你发出去的数据,对方一定能收到呢???我们可以借鉴 TCP 协议的做法(回
复+重发+编号 机制)
1)接收方收到数据后,回复一个确认包,如果你不回复,那么发送端是不会知道接收
方是否成功收到数据的
比如 A 要发数据“{data}”到 B,那 B 收到后,可以回复一个特定的确认包“{OK}”,
表示成功收到。
但是如果只做上面的回复处理,还是有问题,比如 B 收到数据后回复给 A 的数据"{OK}"
的包, A 没收到,怎么办呢???
2)当 A 没有收到 B 的"{OK}“包后,要做定时重发数据,直到成功接收到确认包为止,
再发下面的数据,当然,重发了一定数量后还是没能收到确认包,可以执行一下 ARP 的流程,
防止对方网卡更换或别的原因。
但是这样的话, B 会收到很多重复的数据,假如每次都是 B 回复确认包 A 收不到的话。
3)发送数据的包中加个标识符,比如 A 要发送的数据”{标识符|data}"到 B, B 收到后,
先回复“{OK}"确认包,再根据原有的标识符进行比较,如果标识符相同,则数据丢失,如
果不相同,则原有的标识符 = 接收标识符,且处理数据。
当 A 发送数据包后,没有收到确认包,则每隔 x 秒,把数据重发一次,直到收到确认包
后,更新一下标识符,再进行后一包的数据发送。
经过上面 1), 2), 3)点的做法,则可以保证数据百分百到达对方,当然,标识符用
ID 号来代替更好
CAP
原理指的是,在分布式系统中这三个要素最多只能同时实现两点,不可能三者兼顾。因此在进行分布式架构设计时,必须做出取舍。而对于分布式数据系统,分区容忍性是基本要求,否则就失去了价值。因此设计分布式数据系统,就是在一致性和可用性之间取一个平衡。对于大多数Web应用,其实并不需要强一致性,因此牺牲一致性而换取高可用性,是目前多数分布式数据库产品的方向。
分布式锁应该具备哪些条件:
1、在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行;
2、高可用的获取锁与释放锁;
3、高性能的获取锁与释放锁;
4、具备可重入特性;
5、具备锁失效机制,防止死锁;
6、具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败。
实现方法: