1. BTree的构建原理,查看
数据库很多引擎都是用BTree+作为索引的数据结构。数据库索引的主要是为了更快的查找和定位数据记录。 如果不考虑性能的话,可以使用二叉树来搜索,根据索引的字段表来实现。 二叉树根据左右节点的log2n的复杂度的实现。 但是二叉树存在深度太高的情况,这样查找的深度很多,对于特殊的情况它的复杂都是N, 这样性能不高。 为了解决二叉树的高度问题,提出了M叉树,这个M叉树可以在一个节点上挂多个节点。 但是M叉树也存在一个问题,对于重建索引或者新建节点的时候,可能存在节点大批量的移动的情况。
为了解决这个问题, 采用旋转的概念,也就是平衡树的概念。 通过旋转树的逻辑来处理操作。保持节点的平衡
2. 计数的的概念引用,查看
每个PHP的变量都会有一个计数器,存在一个zval的变量(在5.6版本之前是24个字节用于存储),除了包括变量和类型,还增加了2个字节一个is_ref的引用的数据。 第二个是是refcount,表示引用的计数器的数量和数据的逻辑处理。 所有的符号存在一个符号表中,其中每个符号都有作用域(scope),那些主脚本(比如:通过浏览器请求的的脚本)和每个函数或者方法也都有作用域。
3. LRU的缓存实现
LRU的缓存逻辑的处理操作, LRU的思路一个链表的逻辑操作,在链表的表头操作插入, 如果有热点的数据,在表头进行插入, 如果链表的长度超过了固定的长度, 则擅长链表尾部的节点。
这种算法比较简单,可以比较缓存高校的节点数据, 但是也可能会存在污染的情况。 比如一个访问很集中的情况,次数很多,但是在一定的时间段里面它使用低,这时候很容易出现缓存淘汰的操作。
4. B树和B+树的区别[重点]
1、B+树的层级更少:相较于B树B+每个非叶子节点存储的关键字数更多,树的层级更少所以查询数据更快;
2、B+树查询速度更稳定:B+所有关键字数据地址都存在叶子节点上,所以每次查找的次数都相同所以查询速度要比B树更稳定;
3、B+树天然具备排序功能:B+树所有的叶子节点数据构成了一个有序链表,在查询大小区间的数据时候更方便,数据紧密性很高,缓存的命中率也会比B树高。
4、B+树全节点遍历更快:B+树遍历整棵树只需要遍历所有的叶子节点即可,,而不需要像B树一样需要对每一层进行遍历,这有利于数据库做全表扫描。
B树相对于B+树的优点是,如果经常访问的数据离根节点很近,而B树的非叶子节点本身存有关键字其数据的地址,所以这种数据检索的时候会要比B+树快。
5. memcache算法
分布式算法解析 主要是通过slab块来分配内存的算法逻辑, 对于分布式的算法逻辑操作采用:
-
余数算法逻辑 先获取hashcode的散列值,再除于服务器的台数,根据余数获取服务的节点数
-
散列算法。先算法memcache的散列值, 并将其分不到0~2^32次方的圆上。 如果超过2^32次方还是找不到用户的话, 就将数据保存到第一台memcache上
6. 压力测试
环境:Ubuntu16.04 + Core I5 4核 + 8G内存 PHP7.0.10 脚本:ab -c 100 -n 10000 http://127.0.0.1:9501/ Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.2 0 2 Processing: 0 9 9.6 6 96 Waiting: 0 9 9.6 6 96 Total: 0 9 9.6 6 96
使用wrk来测试性能的情况,看下是否可以处理的能力操作 wrk -t4 -c8 -d60s http://192.168.1.10:8812/hello.php
wrk -t4 -c8 -d60s http://192.168.1.10:8812/hello.php
7. swoole的原理
主要是采用多路复用IO的逻辑来实现,而多路复用的IO是异步非阻塞的操作。 对于要回调的时间写入到红黑树树,这个是自由平等的二叉树,可以保证搜索的速度控制再logN的时间复杂度实现
深入浅出网络编程与Swoole内核,查看
swoole协程原理是由事件驱动和栈切换两步共同完成的实现的。
8. http的三次握手和四次挥手
http的三次握手和四次挥手
四次挥手主要是客户端发送我要中断,服务端接受到指令的时候,发送你的数据我已经收到,并且发送我也没有数据要发送了, 最后客户端发送我已经收到了。
9. ZooKeeper &ZAB 协议&Paxos算法
Paxos 算法应该可以说是 ZooKeeper 的灵魂了。但是,ZooKeeper 并没有完全采用 Paxos算法 ,而是使用 ZAB 协议作为其保证数据一致性的核心算法。另外,在ZooKeeper的官方文档中也指出,ZAB协议并不像 Paxos 算法那样,是一种通用的分布式一致性算法,它是一种特别为Zookeeper设计的崩溃可恢复的原子消息广播算法。
ZAB(ZooKeeper Atomic Broadcast 原子广播) 协议是为分布式协调服务 ZooKeeper 专门设计的一种支持崩溃恢复的原子广播协议。 在 ZooKeeper 中,主要依赖 ZAB 协议来实现分布式数据一致性,基于该协议,ZooKeeper 实现了一种主备模式的系统架构来保持集群中各个副本之间的数据一致性。
10. 跳跃表
- 以顺序list作为基础结构
- 分多个block,每个block第一个元素构成新的list,从而实现分层跳跃
11. 10分钟看懂Docker和K8S,查看
12. 遇到最复杂的事情?
13. 内网一个域名怎么解析多个ip
对于内网的域名的解析主要还是通过负载均衡的处理的方式。通过访问DNS的域名,然后配置多个ip轮询作为负载均衡的策略,这样一个域名的方法,可以解析多个IP
14. 数据库事务隔离机制
事务隔离是数据库事务特征中的一种。 ACID,原子性,一致性,隔离性,持久性。
隔离机制主要是解决事务读写等级的情况。 一般常见的事务有问题有,
-
读未提交:可以读到未提交的数据。这是可以出现脏读,幻读
-
读提交:可以读到提交的数据。这个主要是读取数据的快照,可以解决脏读的问题,不能够解决不可重读的问题。 可以在读取提交的时候,同时进行更新了。 这样就不能够解决不可重读的问题。
-
可重读:主要是针对不可重读的问题,在读取的时候不能够进行更新操作。 也是mysql默认的事务级别。
-
串行化是事务的最高级别,就是一个个排队的执行。 性能比较低。
15. 怎么来保证服务高可用?
服务的高可用主要是来解决服务在使用过程中的遇到问题能够自动容错和快速的恢复,同时系统随着业务增长也可以自动的扩展。
架构的常见问题:单系统的问题和系统间的问题。
单机的处理问题主要包括, 慢查询的问题,影响执行的性能甚至影响锁表和锁库,形成读取的I/O阻塞的,从而影响其性能。
大事务问题:事务执行的时间性阻塞,还有服务的请求超时和重试的问题。以及一些代码影响的系统的执行性能的问题,导致系统不可用或者响应时间太长。
除了单系统的问题,还有系统间的问题。
- 单机负载的问题,对于这样,采用负载均衡,保证不同的机器能够均衡的分配机器的流量
- 熔断机制, 对于大量的使用,采用熔断机制,可以减少系统的稳定性问题。
- 限流,对于服务器性能进行预估,如果超过了服务去的性能和响应需求,则限制流量,保质核心业务的正常使用。
- 对于服务器资源进行隔离,并且对服务的资源进行更加细粒度话的控制,如采用docker对资源控制,对于进程和线程的隔离。
- 对于依赖问题。
检查的清单
| 大分类 | 小分类 | check项目 |
|---|---|---|
| 基础组件依赖 | 缓存 | 挂了是否可用,跟其他系统共用 |
| MYSQL | 跟其他系统共用,慢查询,大事务,连接池监控状况,大表,读写分类,主从延时敏感 | |
| MQ | 挂了是否可用, 依赖于消息发送的顺序 | |
| 日志 | 建立日志不超过30%,使用日志的性能和稳定性 | |
| 其他组件 | 是否有监控的系统来监控 | |
| 依赖于外部环境 | 依赖于外部的上下游的情况 | |
| 核心接口 | 性能问题 | |
| JVM | 基本配置 | 堆栈的配置, 线程的监控和报警, 批量更新和缓存操作 |
| 容量预估 | 高峰期的CPU load,高峰期的内存, 高峰期的磁盘IO,高峰期的网卡,是否三倍冗余 |
16. 分库分表原则,查看
表拆分,大表拆成小表主要是解决减少表记录查询的时间,同时提高数据库的吞吐率,这就是所谓的分表
分表只是解决了查询性能和效率的问题,但对于数据库的并发处理没法带来质的提升, 面对高并发的读写, 当数据库master服务器无法承载写的操作压力时候,不管如何扩展slave服务器都没有意义。 所以要换个思路对于库进行拆分,提高库的写入能力,这就是所谓的分库。
分表包括水平拆分和垂直拆分,以及分区拆分
水平拆分的维度包括
- 水平切分的分片维度,如根据hash来拆分, 根据时间片来拆分
难点在事务的处理。
- 事务补偿机制,对于多段事务保持其最终一致性的实现逻辑
- 事务路由,无论使用上面哪种方法实现分布式事务,都需要对分库分表的多个数据源路由事务,一般通过对Spring环境的配置,为不同的数据源配置不同的事务管理器(TransactionManager)。
- 分库分表引起的问题 问题一:扩容与迁移 在分库分表后,如果涉及的分片已经达到了承载数据的最大值,就需要对集群进行扩容。扩容是很麻烦的,一般会成倍地扩容。
Step1:按照新旧分片规则,对新旧数据库进行双写。
Step2:将双写前按照旧分片规则写入的历史数据,根据新分片规则迁移写入新的数据库。
Step3:将按照旧的分片规则查询改为按照新的分片规则查询。
Step4:将双写数据库逻辑从代码中下线,只按照新的分片规则写入数据。
Step5:删除按照旧分片规则写入的历史数据。
要避免在一个事务中同时修改数据库db0和数据库db1中的表,因为操作起来很复杂,对效率也会有一定的影响。请参考第三章的内容。
要避免在一个事务中同时修改数据库db0和数据库db1中的表,因为操作起来很复杂,对效率也会有一定的影响。请参考第三章的内容。
17. 开源监控系统梳理
-
zabbix,是一个web的界面提供分布式系统监控以及网络监视功能企业级的开源解决方案
-
zabbix可以收集各种网络参数, 保证系统的安全运营, zabbix支持两种方式,一种是zabbix server, 一种是zabbix agent。可以对端口监控,查看远程服务器和网络监视的状态。
-
zenoss Zenoss Core是开源企业级IT管理软件-是智能监控软件,他允许IT管理员依靠单一的WEB控制台来监控网络架构的状态和健康度。Zenoss Core同时也是开源的网络与系统管理软件。
-
HTOP 可以很清晰的查看网络的服务器情况和性能的情况。 包括IO,负载等数据情况。
-
第三方服务器: 监控宝,可以主要是通过探针的方式,来监控多种服务。 不过对于链路监控支持的不是很好。
-
全链路监控,也是系统在使用的。 Zipkin全链路监控,查看
通过统一的trace id来监控整体的链路服务情况,并且把这种服务运用日常的开发报警和日志的问题定位之中。
- 错误日志的监控,可以使用ELK的实现
- grafana是很好的监控界面,可以配置指标显示监控的效果图形。
监控的主要内容:
- 硬件监控
- 系统监控
- 应用监控
- 网络监控
- 流量分析
- 日志监控
- 安全监控
- API监控
- 性能监控
- 业务监控
18. MQ对比之RabbitMQ & Redis ,查看
Redis是轻量级的消息队列,写入和出队列性能都比较高,
RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现的产品,RabbitMQ是一个消息代理,从“生产者”接收消息并传递消息至“消费者”,期间可根据规则路由、缓存、持久化消息。“生产者”也即message发送者以下简称P,相对应的“消费者”乃message接收者以下简称C,message通过queue由P到C,queue存在于RabbitMQ,可存储尽可能多的message,多个P可向同一queue发送message,多个C可从同一个queue接收message
19. redis 热key问题
Redis缓存之穿透、雪崩、热Key问题,查看
热key问题及解决方案
产生的原因: 用户消费的数据远大于生产的数据,如在突发的事件请求的数据大于远超过要写入的数据。就会造成热数据。
我们一般采用缓存+过期时间来解决这个问题, 但是过期后容易集中打到缓存中。 集中出现的两个问题:
- 访问的数据是一个热点key
- 构建缓存需要时间
如果出现以上的问题, 就会出现缓存失效,大量的请求就会绕过redis缓存,而直接查询后端服务的压力,包括服务器和数据库的压力。
解决的方案:
- 对于热点的key设置永不过期,这是从物理上进行来设置不过期,而通过代码的改进来定时把任务进行修改key从而满足其效果数据的情况。
- 采用互斥锁的逻辑,只让一个线程来构建缓存,(查询数据库来重建缓存) 其他线程都要等待, 直到的第一个线程构建完成,直接查询缓存的数据信息。
缓存穿透问题
场景描述:缓存查询某个key的时候会从数据库中来读取,如果缓存层查询不到就会到查询存储层去读取数据,然后就失去了缓存的意义,在一定的程度上影响数据库压力。 解决方案: 对于不存在的key放到布隆过滤器(hash)的数据结构,把所有的可能存在的数据hash到一个bitmap里面, 对于不存在的数据会被这个bitmap进行过滤。如果查询一个数据为空, 对于为空的数据,我们也会进行缓存的操作。 不过设置时间不超过5分钟。布隆过滤器重要是解决一个排序的数据,按照位来存储,其实构建的一个巨大的稀疏矩阵,对于数据过滤非常重要,对于遍历数据的时候如果出现0,则表示没有合适的数据,并进行过滤使用
缓存失效带来的雪崩问题
这种是来自于key的大面积失效,带来的后端服务查询数据的压力,从而导致数据库的压力。 一个简单的方法对于缓存的值都加上一个随机值,这样在访问的时候,不容易出现大面积的失效,从而查询后端的服务。
同时我们可以在redis和数据库之间增加互斥锁(使用互斥锁(mutex key))或者查询队列,来缓解对数据的压力。 对于查询比较大的情况,可以通过队列的等待来解决。
public String get(key) {
String value = redis.get(key);
if (value == null) { //代表缓存值过期
//设置3min的超时,防止del操作失败的时候,下次缓存过期一直不能load db
if (redis.setnx(key_mutex, 1, 3 * 60) == 1) { //代表设置成功
value = db.get(key);
redis.set(key, value, expire_secs);
redis.del(key_mutex);
} else { //这个时候代表同时候的其他线程已经load db并回设到缓存了,这时候重试获取缓存值即可
sleep(50);
get(key); //重试
}
} else {
return value;
}
}
20. lnmp高并发优化简介
增加work_rlimit_nofile和worker_connections数量,并禁用keepalive_timeout。
保持处理的连接数,并禁用keepalive的处理, nginx的配置参数主要集中在worker进程数量,使用的异步事件IO建立的连接数。也可以对nginx和php-fpm的优化配置,包括nginx 启动之后,对于php进程不够,可以设置pm.max_children来设置其进程数量。
php-fpm的调参数:动态和静态的情况下启动的线程和进程的数量的情况。
思路
内核层面:加大连接数,加快tcp回收
mysql层面:增大连接数, 关闭磁盘noatime, 使用SSD硬盘
php层面:用长连接,节省连接数 用内存缓存(memcached/redis),减轻mysql压力
注意 内存缓存适用于缓存复杂的sql查询。因为php与memcached也要建立tcp连接,所以简单的sql查询不需要用缓存。
21. 高并发环境在nginx和php层面要考虑注意什么
对在高并发的情况下,保持性能的高可用。 对于这样的情况下,nginx 层面根据机器的情况下计算下nginx的配置的worker数量和connections的数量,并且保证进程服务的稳定。
PHP主要是接受Nginx的fastcgi的报文。是不错的选择哦。
21.1 nginx配置踩过什么坑
22. 聊聊服务稳定性保障这些事 ,查看
22.1 稳定性的重要性
22.2 保障策略架构篇
- 从架构层面保障稳定性,常见的策略包括限流,降级,隔离,超时,重试和集群等。
限制流量的大小,降低请求的流量,降级的目的很降级的目的比较简单(保证基础服务的可用,保证核心业务的可用,对于辅助的业务不进行访问正常), 第一个是保障服务器基本可用,第二个是保障服务的核心服务可用。降级是怎么一个思路呢?一般降级的每个策略都是针对一个场景,预想特定场景下需要要解决什么问题;然后再梳理在这个场景下需要保留哪些核心基本服务;
-
限流:限流常见的是漏桶算法和令牌算法。思路就是在把所有的流量是一个池子,流动的速率是稳定的,孔的高度也是稳定的。漏桶算法能够保证请求的负载时间长, 即每秒能够处理的请求数量。
-
令牌算法:令牌桶算法也是有一个桶,但是桶不漏,桶里面放了一些令牌,每来一个请求就在桶里拿一个令牌,如果没有令牌它就可以等待,令牌满了就不再往里面加令牌。这样方法基本上也可以达到一个限流的目的。令牌桶算法和漏桶算法的一个显著区别是漏桶算法在后端取请求量时,基本上漏的速率是一样的,但是令牌桶算法中后端部分可以有突发请求,如果桶满了,可以将桶里所有令牌都拿走。
-
降级: 一般情况下,系统上线之后总会遇到一些不稳定情况,比如 redis 挂掉,甚至后端数据库 My SQL 挂掉。当出现不稳定情况之后,系统如何保证继续提供这些服务。
22.3 保障策略流程篇
对于做了好了基本的策略,我们进一步采用, 线上的保证其稳定性。 Code Review: 来对代码的审核,提高代码的质量,并且对代码的进行整理。
压测: 压测的目的第一保持系统的稳定性。在高并发的是时候也可以保持系统的稳定性, 因为在一定的流量的基础上。检查性能的抗压能力, 检查系统的能够承受的QPS
灰度: 灰度目的是小范围试错,尽量发现问题。只让某个地区的人先访问其特性, 遇到问题的及时反馈
监控: 自动化及时发现问题。监控的问题发现的事情。
全链路的监控服务,来保持系统的稳定性。
23. nginx配置踩过什么坑
Nginx的处理,
24. 其他问题
24.1 PHP7 opcache缓存清理问题,查看
opcache 一方面提高了php的性能,但是另一方面,对于线上发版本来说,很容易出现缓存一直存在的情况。 考虑解决该问题的方式,主要集中在两个方面, 一个是设置opcache的失效时间,另一个是通过手动或者自动更新文件,清理opcache的缓存。 对于可以时间使用调用opcache_reset 来重置缓存,也可以使用发版本的rsync来更新同步缓存。