资讯详情

PHP进阶面试题

比较一下php和go的区别?

Go是静态语言。PHP是一种动态语言。 PHP 每个请求进来都会创建 fpm-worker 过程导致系统并发高 CPU 在创建过程中会产生频繁的费用, Go 不会。 golang 先编译后执行。因为编译,即使不好Golang代码也会比好PHP提高性能的代码。 由于多线程技术的改进Golang降低了部署规模,降低了内存占用, Golang降低企业间接成本。

什么是守护过程?

守护进程(daemon)这是一个特殊的过程,它的生命周期很长,它在后台运行,没有控制终端(以确保保护过程不会收到终端的各种信号)。 比如:crontab、sshd、nginx以保护过程的形式程的形式运行,以确保服务能够正常提供。

如何实现守护过程?

fork子进程,父进程退出(当前子进程会成为init子进程) 子进程调用setsid(),打开新的会话,成为新的会话组长,并在终端上释放相关关系 再次fork子过程,父过程退出(可防止会话组长重新申请打开终端) 关闭打开的文件描述符 改变当前工作目录chdir 清除进程的umask

PHP实现

/** * daemon(守护过程) PHP实现 * @author zhjx922 */ $pid = pcntl_fork(); if ($pid == -1) { 
         die(创建子过程失败); } else if ($pid) { 
         ///第一次退出父亲的过程 exit(0); } //setsid posix_setsid(); echo "成功输出,脱离终端" . PHP_EOL; sleep(5); $pid = pcntl_fork(); if ($pid == -1) { 
         die(创建子过程失败); } else if ($pid) { 
         /fork子进程出来) exit(0); } echo "仍然可以输出" . PHP_EOL; sleep(5); //关闭各种描述符
@fclose(STDOUT);
@fclose(STDERR);
$STDOUT = fopen('/dev/null', "a");
$STDERR = fopen('/dev/null', "a");
chdir('/');
umask(0);
echo "这里不会输出, ps aux | grep daemon.php 查看进程,20s后退出" . PHP_EOL;
sleep(20);

注意事项: php daemon.php &这样使用,当关闭终端后,当前php进程也会同时关掉 nohup php daemon.php > daemon.log &终端关闭后,依然会继续运行 使用supervisor

如何理解框架?

框架是构成一类特定软件可复用设计的一组相互协作的类。框架规定了应用的体系结构。定义了整体结构,类和对象的分隔,各部分的主要责任,类和对象怎么协作,以及控制流程。框架预定义了这些设计参数,以便于应用设计者或实现者能集中精力于应用本身的特定细节。框架记录了其应用领域的共同的设计决策。因而框架更强调设计复用,尽管框架常包括具体的立即可用的子类

框架常用的主要设计模式有哪些?

单例(Singleton):保证一个类仅有一个实例,并提供一个访问它的全局访问点 抽象工厂(Abstract Factory):提供一个创建一系列相关或相互依赖对象的接口 工厂方法(Factory Method):定义一个用于创建对象的接口,让子类决定哪一个类实例化 原型(Prototype):用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象 适配器(Adapter):将一个类的接口转换成期望的另一个接口 代理(Proxy):为其他对象提供一个代理以控制对这个对象的访问 备忘录(Memento):备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捉住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态 观察者(Observer):在对象间定义一个一对多的联系性,由此当一个对象改变了状态,所有其他相关的对象会被通知并且自动刷新 策略(Strategy):定义一个算法的系列,将其各个分装,并且使他们有交互性。策略模式使得算法在用户使用的时候能独立的改变

类的静态调用和实例化调用

占用内存 静态方法在内存中只有一份,无论调用多少次,都是共用的 实例化不一样,每一个实例化是一个对象,在内存中是多个的 不同点 静态调用不需要实例化即可调用 静态方法不能调用非静态属性,因为非静态属性需要实例化后,存放在对象里 静态方法可以调用非静态方法,使用 self 关键字。php 里,一个方法被self::后,自动转变为静态方法 调用类的静态函数时不会自动调用类的构造函数

接口和抽象的区别

抽象用于描述不同的事物,接口用于描述事物的行为。

PHP 不实例化调用方法

静态调用、使用 PHP 反射方式。

有哪些常见的 php.ini 配置选项

配置选项 名字 默认 备注

short_open_tag "1" 是否开启缩写形式(<? ?>)
precision "14" 浮点数中显示有效数字的位数
disable_functions "" 禁止某些函数
disable_classes "" 禁用某些类
expose_php "" 是否暴露 PHP 被安装在服务器上
max_execution_time 30 最大执行时间
memory_limit 128M 每个脚本执行的内存限制
error_reporting NULL 设置错误报告的级别E_ALL& ~E_NOTICE& ~E_STRICT& ~E_DEPRECATED
display_errors "1" 显示错误
log_errors "0" 设置是否将错误日志记录到 error_log 中
error_log NULL 设置脚本错误将被记录到的文件
upload_max_filesize "2M" 最大上传文件大小
post_max_size "8M" 设置POST最大数据限制

php -ini | grep short_open_tag //查看 php.ini 配置

动态设置 ini_set(string $varname , string $newvalue);

ini_set(‘date.timezone’, ‘Asia/Shanghai’); //设置时区 ini_set(‘display_errors’, ‘1’); //设置显示错误 ini_set(‘memory_limit’, ‘256M’); //设置最大内存限制

MySQL、MySQLi、PDO 区别

MySQL 允许 PHP 应用与 MySQL 数据库交互的早期扩展 提供了一个面向过程的接口,不支持后期的一些特性 MySQLi 面向对象接口 prepared 语句支持 多语句执行支持 事务支持 增强的调试能力 PDO PHP 应用中的一个数据库抽象层规范 PDO 提供一个统一的 API 接口,无须关心数据库类型 使用标准的 PDO API,可以快速无缝切换数据库

php代码执行过程是怎样的?

PHP 代码 => 启动 php 及 zend 引擎,加载注册拓展模块 => 对代码进行词法/语法分析 => 编译成opcode(opcache) => 执行 opcode PHP7 新增了抽象语法树(AST),在语法分析阶段生成 AST,然后再生成 opcode 数组。

怎么评价对象关系映射/ORM?

优点 缩短编码时间、减少甚至免除对 model 的编码,降低数据库学习成本 动态的数据表映射,在表结构发生改变时,减少代码修改 可以很方便的引入附加功能(cache 层) 缺点 映射消耗性能、ORM 对象消耗内存 SQL 语句较为复杂时,ORM 语法可读性不高(使用原生 SQL)

有哪些 PHP 支持回调的函数,如何实现?

数组函数: array_map、array_filter、array_walk、usort 自己实现的思路: is_callable + callbacks + 匿名函数实现

PHP 数组底层怎么实现的?

关键点: (HashTable + Linked list) PHP 数组底层依赖的散列表数据结构,定义如下(位于 Zend/zend_types.h)。 数据存储在一个散列表中,通过中间层来保存索引与实际存储在散列表中位置的映射。 由于哈希函数会存在哈希冲突的可能,因此对冲突的值采用链表来保存。 哈希表的查询效率是o(1),链表查询效率是o(n);因此PHP数据索引速度很快;但是相对比较占用空间。

PHP内存管理机制与垃圾回收机制

参考答案:http://www.cnblogs.com/zk0533/p/5667122.html php的内存管理机制是:预先给出一块空间,用来存储变量,当空间不够时,再申请一块新的空间。 存储变量名,存在符号表。 变量值存储在内存空间。 在删除变量的时候,会将变量值存储的空间释放,而变量名所在的符号表不会减小。 在5.2版本或之前版本,PHP会根据 引用计数 (refcount)值来判断是不是垃圾,如果refcount值为0,PHP会当做垃圾释放掉,这种回收机制有缺陷,对于环状引用的变量无法回收。 在5.3之后版本改进了垃圾回收机制。具体如下: 如果发现一个zval容器中的refcount在增加,说明不是垃圾; 如果发现一个zval容器中的refcount在减少,如果减到了0,直接当做垃圾回收; 如果发现一个zval容器中的refcount在减少,并没有减到0,PHP会把该值放到缓冲区,当做有可能是垃圾的怀疑对象; 当缓冲区达到了临界值,PHP会自动调用一个方法去遍历每一个值,如果发现是垃圾就清理。

为什么使用B+树,而不是用B*树

因为B*树非叶子节点使用了指向兄弟节点的指针。如果一个节点满了之后,自己的兄弟节点还没有满,需要将一部分数据转移到自己的兄弟节点去。如果兄弟节点也满了,就在自己和兄弟节点之间添加新的节点。因为兄弟之间分配新节点的概率还是比较低的,所以空间利用率还是比较高的。 是B+树的变体,在B+树的非根和非叶子结点再增加指向兄弟的指针;

除了主键索引,还用过什么

唯一索引 普通索引 覆盖索引 前缀索引 联合索引

主键索引和唯一索引的区别

主键一定会创建一个唯一索引,但是有唯一索引的列不一定是主键; 主键不允许为空值,唯一索引列允许空值; 一个表只能有一个主键,但是可以有多个唯一索引; 主键可以被其他表引用为外键,唯一索引列不可以; 主键是一种约束,而唯一索引是一种索引,是表的冗余数据结构,两者有本质的差别 最左匹配原则案例 where a = 1 and b=1 and c = 1. 能命中abc where a = 1 and b > 1 and c = 1 不能命中c 因为b是范围索引。范围索引的话,意味着b可能是无序的。 where a > 1 and b = 1 and = 1 bc不能命中索引,因为范围查询是不能命中索引的。

order by 能用上索引么?

CREATE TABLE t ( id int(11) NOT NULL, city varchar(16) NOT NULL, name varchar(16) NOT NULL, age int(11) NOT NULL, addr varchar(128) DEFAULT NULL, PRIMARY KEY (id), KEY city (city)) ENGINE=InnoDB;

这种情况下对name进行排序的话,是不会用上索引的。因为是对全文进行排序。 select city,name,age from t where city=‘杭州’ order by name limit 1000 ;

如果认为字段值过大的话,会进行rowid排序,也就是每行,根据city 取到行数据之后。只取 id 和 name,然后去按name进行排序。这种情况下,其实是内存不够的情况。这种情况下,name是无序的,需要多一次排序的操作。 如果在city 和name上面建立联合索引的话,根据city取的值,name就是有序的,减少排序的操作。 alter table t add index city_user(city, name);

这种情况下, 不需要临时表,也不需要排序。 using index 说明使用了覆盖索引,覆盖索引的效率还是比较高的。 mysql索引的底层B+树,说说为什么使用B+树,跟红黑树有什么区别,B树和B+树的区别? 主要考虑的是IO影响吧。因为B+ 树只有叶子节点存储数据,B树内部也存储数据。在查询相同数据量的情况下,B树高度更高,IO次数更多,然后只能一点点加载数据页。 B树的话,所有的节点都是数据地址。需要在内部节点和叶子之间去查询数据。b树的分支节点也有数据。 b树范围查询只能中序遍历。 B+树只有叶子节点数据,而且叶子节点之间由链表构成的,在叶子节点直接顺序查询会比较快。b+树的数据都集中在叶子节点。分支节点只负责索引。b+树的层高 会小于 B树 平均的Io次数会远大于 B+树(因为B+树是顺序查找)b+树更擅长范围查询。叶子节点 数据是按顺序放置的双向链表。 b+树可以把索引完全加载至内存中。支持多路,多路的好处:可以每次只加载一个节点的数据进去,因为内存的容量是有限的。【这个就是多路的好处了

MYSQL分页limit速度太慢,如何优化?

为什么要对数据库进行主从分离? 参考答案:https://my.oschina.net/candiesyangyang/blog/203425 索引查找在Linux的磁盘上是怎么操作的 innodb为什么必须要有主键索引? 使用InnoDB引擎,数据在硬盘上是如何存放的? 可参考:https://blog.csdn.net/hollis_chuang/article/details/113153569 聚族索引与非聚族索引的区别 按物理存储分类:聚簇索引(clustered index)、非聚簇索引(non-clustered index) 聚簇索引的叶子节点就是数据节点,而非聚簇索引的叶子节点仍然是索引节点,只不过有指向对应数据块的指针。 数据库主从复制 M-S 是怎么同步的?是推还是拉?会不会不同步?怎么办? 如何保障数据的可用性,即使被删库了也能恢复到分钟级别。你会怎么做? 数据库连接过多,超过最大值,如何优化架构。从哪些方便处理? int 占多少字节? bigint 呢?int (3) 和 int (11) 有区别吗? 可以往 int (3) 里存 1 亿吗? varchar 最长多少? drop delete truncate的区别? drop 删除表和数据 delete 删除数据 带where truncate 不带where 的删除,不太安全。 where in (几个) where in (几万个) 有什么区别 select * from single_table where key1 in ('aa), ‘aa1’, ‘aa2’, …, ‘zz100’); mysql在5.7.3之前的版本是的eq_range_index_dive_limit的默认值是10,在5.7.3之后是200. 当in语句的单点区间数量大于等于eq_range_index_dive_limit的值时,就不会使用index dive来计算各个单点区间对应的索引记录条数,而是使用索引统计数据。 例如rows是9693,key1列的不重复值为968,所以key1列的平均重复次数为:9693/968 = 10条。 当in的数量为20000个时,意味着有20000个单点区间的时候,就直接使用统计数据来估算对应的记录条数。每个区间对应10条,对应的回表记录数就是20000 * 10 = 200000条。 当in的数量为几个的时候,由于key1列只是一个普通索引的话,每个单点的值对应多少条记录并不确定。计算方式就是直接获取索引对应的B+树的区间最左记录和区间最右记录,然后再计算这两条记录之间有多少条记录。 这种直接访问索引对应B+树来计算某个扫描区间内对应的索引记录条数的方式就是index dive 内容来自《MySQL是怎样运行的》

mysql --help | grep max-allowed-packet mysql: [Warning] World-writable config file ‘/usr/local/etc/my.cnf’ is ignored. --max-allowed-packet=# max-allowed-packet 16777216 in 没有大小限制。但是受max-allowed-packet的限制,最多也就2000个吧

innodb 的索引组织方式?

聚簇索引必须要很清楚,注意 innodb 聚簇索引叶子结点保存的是完整数据,innodb 普通索引叶子保存的是记录的主键,myisam 索引叶子保存的是记录的位置 / 偏移量。 数量级在多少适合分表? MySQL 单表容量在500万左右,性能处于最佳状态,此时,MySQL 的 BTREE 索引树高在3~5之间

BTree 与 BTree-/BTree+ 索引原理是什么?

BTree 二叉树导致树高度非常高,逻辑上很近的节点,物理上非常远,无法利用局部性,IO 次数多,查找效率低 BTree- 每个节点都是二元数组[key,data],所有节点都可以存储数据,key 为索引,data 为索引外的数据。插入删除数据会破坏 BTree 性质,插入数据时候,需要对数据进行分裂、合并、转移等操作保持 BTree 性质,造成 IO 操作频繁 BTree+ 非叶子节点不存储 data,只存储索引 key,只有叶子节点才存储 data MySQL中的 BTree+ 在经典 BTree+ 的基础上进行了优化,增加了顺序访问指针。在 BTree+ 的每个叶子节点增加了一个指向相邻叶子节点的指针,形成了带顺序访问指针的 BTree+,提高了区间访问性能。 JOIN和UNION区别 join 是两张表做交连后里面条件相同的部分记录产生一个记录集, union是产生的两个记录集(字段要一样的)并在一起,成为一个新的记录集 。

mysql常见问题和解决思路?

引《mysql45讲》里面的一个留言 数据库——解决数据存储的问题 WAL——解决数据一致性问题 多线程——解决性能差异的问题 ——解决多线程并发导致数据不一致的问题 索引——解决数据查询或者操作慢的问题 日志——解决数据备份、同步、恢复等问题 数据库主备——解决数据高可用的问题 数据库读写分离——解决数据库压力的问题 数据库分库分表——解决数据量大的问题

死锁产生原因是什么?

多个事务在同一资源上相互占用,并请求锁定对方占用资源,从而导致恶性循环的现象 InnoDB 目前处理方法:将持有最少行级排他锁的事务进行回滚。

什么是mysql的锁机制,以及什么是死锁,以及发生死锁的场景?

MySQL的锁机制,就是数据库为了保证数据的一致性而设计的面对并发场景的一种规则。最显著的特点是不同的存储引擎支持不同的锁机制,InnoDB支持行锁和表锁,MyISAM支持表锁。 表锁就是把整张表锁起来,特点是加锁快,开销小,不会出现死锁,锁粒度大,发生锁冲突的概率高,并发相对较低。 行锁就是以行为单位把数据锁起来,特点是加锁慢,开销大,会出现死锁,锁粒度小,发生锁冲突的概率低,并发度也相对表锁较高。 锁等待是指一个事务过程中产生的锁,其他事务需要等待上一个事务释放它的锁,才能占用该资源,如果该事务一直不释放,就需要继续等待下去,直到超过了锁等待时间,会报一个超时错误。

出现死锁的问题并不可怕,解决死锁通常有什么办法?

不要把无关的操作放到事务里,小事务发生冲突的概率较低。 如果不同的程序会并发存取多个表,应尽量约定以相同的顺序来访问表,这样事务就会形成定义良好的查询并且没有死锁。 尽量按照索引去查数据,范围查找增加了锁冲突的可能性。 对于非常容易产生死锁的业务部分,可以尝试升级锁粒度,通过表锁定来减少死锁产生的概率。 引用:https://www.cnblogs.com/xxcn/p/9941365.html InnoDB的锁 InnoDB的索引与行记录存储在一起,这一点和MyISAM不一样; InnoDB的聚集索引存储行记录,普通索引存储PK,所以普通索引要查询两次; 记录锁锁定索引记录; 间隙锁锁定间隔,防止间隔中被其他事务插入; 临键锁锁定索引记录+间隔,防止幻读; 锁的类型 全局锁,用来做全库逻辑备份。。Flush tables with read lock 这个是一个全局锁。 表锁,表级锁,lock tables t1 read, t2 write; unlock tables 表锁的语法是 lock tables … read/write 另一类表级的锁是 MDL(metadata lock)(默认会启动) 如果想要拿到表的结构,可以选择等待多长时间,如果等待能拿到的话,最好。拿不到的话,也不会阻塞。 ALTER TABLE tbl_name NOWAIT add column … ALTER TABLE tbl_name WAIT N add column …

如何实现 MySQL 的读写分离?

其实很简单,就是基于主从复制架构,简单来说,就搞一个主库,挂多个从库,然后我们就单单只是写主库,然后主库会自动把数据给同步到从库上去。

MySQL 主从复制原理的是啥?

主库将变更写入 binlog 日志,然后从库连接到主库之后,从库有一个 IO 线程,将主库的 binlog 日志拷贝到自己本地,写入一个 relay 中继日志中。接着从库中有一个 SQL 线程会从中继日志读取 binlog,然后执行 binlog 日志中的内容,也就是在自己本地再次执行一遍 SQL,这样就可以保证自己跟主库的数据是一样的。 这里有一个非常重要的一点,就是从库同步主库数据的过程是串行化的,也就是说主库上并行的操作,在从库上会串行执行。所以这就是一个非常重要的点了,由于从库从主库拷贝日志以及串行执行 SQL 的特点,在高并发场景下,从库的数据一定会比主库慢一些,是有延时的。所以经常出现,刚写入主库的数据可能是读不到的,要过几十毫秒,甚至几百毫秒才能读取到。 而且这里还有另外一个问题,就是如果主库突然宕机,然后恰好数据还没同步到从库,那么有些数据可能在从库上是没有的,有些数据可能就丢失了。 所以 MySQL 实际上在这一块有两个机制,一个是半同步复制,用来解决主库数据丢失问题;一个是并行复制,用来解决主从同步延时问题。 这个所谓半同步复制,也叫 semi-sync 复制,指的就是主库写入 binlog 日志之后,就会将强制此时立即将数据同步到从库,从库将日志写入自己本地的 relay log 之后,接着会返回一个 ack 给主库,主库接收到至少一个从库的 ack 之后才会认为写操作完成了。 所谓并行复制,指的是从库开启多个线程,并行读取 relay log 中不同库的日志,然后并行重放不同库的日志,这是库级别的并行。

MySQL 主从同步延时问题

以前线上确实处理过因为主从同步延时问题而导致的线上的 bug,属于小型的生产事故。 是这个么场景。有个同学是这样写代码逻辑的。先插入一条数据,再把它查出来,然后更新这条数据。在生产环境高峰期,写并发达到了 2000/s,这个时候,主从复制延时大概是在小几十毫秒。线上会发现,每天总有那么一些数据,我们期望更新一些重要的数据状态,但在高峰期时候却没更新。用户跟客服反馈,而客服就会反馈给我们。 我们通过 MySQL 命令: show status

查看 Seconds_Behind_Master,可以看到从库复制主库的数据落后了几 ms。 一般来说,如果主从延迟较为严重,有以下解决方案: 分库,将一个主库拆分为多个主库,每个主库的写并发就减少了几倍,此时主从延迟可以忽略不计。【此时是主库的执行性能可能不好】 打开 MySQL 支持的并行复制,多个库并行复制。如果说某个库的写入并发就是特别高,单库写并发达到了 2000/s,并行复制还是没意义。 重写代码,写代码的同学,要慎重,插入数据时立马查询可能查不到。 如果确实是存在必须先插入,立马要求就查询到,然后立马就要反过来执行一些操作,对这个查询设置直连主库。不推荐这种方法,你要是这么搞,读写分离的意义就丧失了。

一个大表(数据有1000w)该怎么加索引?

存在锁住表的可能哦。 建一个一样的 tpm表,给 tmp表加索引,然后两个表rename,给主表加索引,再RENAME回来,把TMP表的 新增数据在主表中没有的给INSERT回主表。

如何修改worker 进程数?

在 conf/nginx.conf 文件中修改 worker_processes 数字即可。

Nginx 基本命令有哪些?

./nginx -s stop ./nginx -s quit ./nginx -s reload ./nginx ./nginx -t Nginx进程模型

Nginx 抢占机制

怎么修改nginx打印的日志格式?

Nginx 服务器提供了一个 HttpLogModule 模块,可以通过它来设置日志的输出格式。

Nginx 日志格式中,有很多参数,总结如下: 参数 说明 示例 $remote_addr 客户端地址 14.116.133.170 $remote_user 客户端用户名称 – $time_local 访问时间和时区 03/Mar/2019:16:43:53 +0800 $request 请求的URI和HTTP协议 “GET /city/static/js/illegals/vehicle-search.js HTTP/1.1” $http_host 请求地址,即浏览器中你输入的地址(IP或域名) www.super.com 192.168.118.15 $status HTTP请求状态 200 $upstream_status upstream状态 200 $body_bytes_sent 发送给客户端文件内容大小 1547 $http_referer url跳转来源 https://www.baidu.com/ $http_user_agent 用户终端浏览器等信息 Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0 $ssl_protocol SSL协议版本 TLSv1 $ssl_cipher 交换数据中的算法 RC4-SHA $upstream_addr 后台upstream的地址,即真正提供服务的主机地址 192.168.118.16:8080 $request_time 整个请求的总时间 0.205 $upstream_response_time 请求过程中,upstream响应时间 0.002

通过更改这里,可以达到想要的结果,如果想打印post请求传参,可以通过安装第三方组件来完成。

简单的说下nginx优化的点

1.使用epoll模型 2.提高进程数、打开连接数 3.启用gzip压缩传输 4.为静态文件启用缓存 5.Timeouts设置 6.防盗链设置 7.非法脚本 8.防止ddoc攻击 9.禁止恶意域名解析 10.隐藏版本信息

keepalived是什么?

keepalived最初是专为LVS负载均衡软件设计的,用来管理并监控LVS集群系统中各个服务节点的状态,后来又加入了实现高可用的VRRP功能。keepalived除了能够管理LVS软件外,还能支持其他服务的高可用解决方案。 keepalived通过VRRP协议实现高可用功能的。VRRP(Virtual Router Redundancy Protocol)虚拟路由冗余协议。VRRP出现的目的就是为了解决静态路由单点故障问题,它能保证当个别节点宕机时,整个网络可以不间断地运行。 keepalived高可用故障转移原理是什么? keepalived高可用服务之间的故障转移,是通过VRRP来实现的。在keepalived服务工作时,主Master节点会不断地向备节点发送(多播的方式)心跳消息,用来告诉备Backup节点自己还活着。 当主节点发生故障时,无法给备节点发送心跳消息,如果备节点无法继续检测到来自主节点的心跳。就会调用自身的接管程序,接管主节点的IP资源和服务。当主节点恢复时,备节点又会释放主节点故障时自身接管的IP资源和服务,恢复到原来的备用角色。

缓存不一致怎么办?

问题:先更新数据库,再删除缓存。如果删除缓存失败了,那么会导致数据库中是新数据,缓存中是旧数据,数据就出现了不一致。 解决思路:先删除缓存,再更新数据库。如果数据库更新失败了,那么数据库中是旧数据,缓存中是空的,那么数据不会不一致。因为读的时候缓存没有,所以去读了数据库中的旧数据,然后更新到缓存中。 ROB的原理是什么? copy on write。父进程会fork一个子进程,父进程和子进程共享内存空间。父进程继续提供读写服务,写脏的页面数据会继续和子进程区分开来。 你给出两个词汇就可以了,fork和cow。fork是指redis通过创建子进程来进行RDB操作,cow指的是copy on write,子进程创建后,父子进程共享数据段,父进程继续提供读写服务,写脏的页面数据会逐渐和子进程分离开来。

除了五种常见数据类型, 还有其他的数据类型么?

string 可以用来计数,缓存,分布式锁 hash 可以用来保存用户的一些属性信息,用户的详情页 list 可以用来做队列,可以用来做栈,可以用来做数据, 可以维护一个评论列表。lrange区间操作。 set 可以用来做 交集 并集 差集,微博抽奖,随机事件问题。无序、去重 sorted set 可以用来做排行榜,带权重的队列。 bitmap 用来保存用户的登录信息,可以查询最近几个月的登录情况:bitop 可以用来做and or意味着有更多的选择。 pub/sub 发布订阅 stream hyperloglog 布隆过滤器器(滑动窗口) stream的备注:支持多播的可持久化的消息队列。 Stream 的消费模型借鉴了 Kafka 的消费分组的概念,它弥补了 Redis Pub/Sub 不能持久化消息的缺陷。但是它又不同于 kafka,Kafka 的消息可以分 partition,而 Stream 不行。如果非要分 parition 的话,得在客户端做,提供不同的 Stream 名称,对消息进行 hash 取模来选择往哪个 Stream 里塞。

分布式锁如何实现?

单机采用set nx 就可以了。最好设计过期时间,防止锁不释放的情况。 // 获取锁 // NX是指如果key不存在就成功,key存在返回false,PX可以指定过期时间 SET anyLock unique_value NX PX 30000 // 释放锁:通过执行一段lua脚本 // 释放锁涉及到两条指令,这两条指令不是原子性的 // 需要用到redis的lua脚本支持特性,redis执行lua脚本是原子性的 if redis.call(“get”,KEYS[1]) == ARGV[1] then return redis.call(“del”,KEYS[1]) else return 0 end

因为redis大部分是单机部署,如果master加锁成功之后,突然宕机了怎么办呢? 会出现锁丢失的情况。 这个时候就得需要redlock锁了。只要大多数(半数以上的机器)加锁成功了,就算是加锁成功了。只要加锁时间小于当前时间,就是加锁成功了。其他的节点就得需要不断的来轮询了。

简述Redlock算法

在Redis的分布式环境中,我们假设有N个Redis master。这些节点完全互相独立,不存在主从复制或者其他集群协调机制。之前我们已经描述了在Redis单实例下怎么安全地获取和释放锁。我们确保将在每(N)个实例上使用此方法获取和释放锁。在这个样例中,我们假设有5个Redis master节点,这是一个比较合理的设置,所以我们需要在5台机器上面或者5台虚拟机上面运行这些实例,这样保证他们不会同时都宕掉。 为了取到锁,客户端应该执行以下操作: 获取当前Unix时间,以毫秒为单位。 依次尝试从N个实例,使用相同的key和随机值获取锁。在步骤2,当向Redis设置锁时,客户端应该设置一个网络连接和响应超时时间,这个超时时间应该小于锁的失效时间。例如你的锁自动失效时间为10秒,则超时时间应该在5-50毫秒之间。这样可以避免服务器端Redis已经挂掉的情况下,客户端还在死死地等待响应结果。如果服务器端没有在规定时间内响应,客户端应该尽快尝试另外一个Redis实例。 客户端使用当前时间减去开始获取锁时间(步骤1记录的时间)就得到获取锁使用的时间。当且仅当从大多数(这里是3个节点)的Redis节点都取到锁,并且使用的时间小于锁失效时间时,锁才算获取成功。 如果取到了锁,key的真正有效时间等于有效时间减去获取锁所使用的时间(步骤3计算的结果)。 如果因为某些原因,获取锁失败(没有在至少N/2+1个Redis实例取到锁或者取锁时间已经超过了有效时间),客户端应该在所有的Redis实例上进行解锁(即便某些Redis实例根本就没有加锁成功)。

主从同步是怎么实现的?

因为单机QPS是有上限的。 当启动一个slave的时候,他发送psync给master。如果是首次连接master,那么master会启动一个线程,进行全量的rdb快照,然后发送给slave。然后把新的请求写到缓存里面,然后slave会执行rdb文件,然后写到自己的本地。然后再读取master里面新增的请求。

说一说你对redis集群架构的理解

redis cluster 着眼于可扩展。当单个redis不足时,使用cluster进行分片存储。。 来看 Redis 的高可用。Redis 支持主从同步,提供 Cluster 集群部署模式,通过 Sentine l哨兵来监控 Redis 主服务器的状态。当主挂掉时,在从节点中根据一定策略选出新主,并调整其他从 slaveof 到新主。 选主的策略简单来说有三个: slave 的 priority 设置的越低,优先级越高; 同等情况下,slave 复制的数据越多优先级越高; 相同的条件下 runid 越小越容易被选中。 在 Redis 集群中,sentinel 也会进行多实例部署,sentinel 之间通过 Raft 协议来保证自身的高可用。 Redis Cluster 使用分片机制,在内部分为 16384 个 slot 插槽,分布在所有 master 节点上,每个 master 节点负责一部分 slot。数据操作时按 key 做 CRC16 来计算在哪个 slot,由哪个 master 进行处理。数据的冗余是通过 slave 节点来保障。

redis的Sentinal哨兵模式是什么?

就是高可用,master宕机之后,会将slave提升为master继续提供服务。 哨兵组件的作用: 集群监控:负责监控 Redis master 和 slave 进程是否正常工作。 消息通知:如果某个 Redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员。 故障转移:如果 master node 挂掉了,会自动转移到 slave node 上。 配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址。 说一说数据类型的底层实现 string -> int string hash -> ziplist hashable zset -> ziplist skiplist set-> intset hash list -> ziplist linkedlist https://mp.weixin.qq.com/s/GLqZf-0sLQ7nnJ8Xb9oVZQ

redis的事件模型是什么?

select epoll select 是每次去拿文件描述符去查,看哪些符合条件,然后去执行 epoll 是采用事件监听的形式,只会执行符合条件的事件。

keys读取命令为什么禁用?

key会堵塞。所以,最好还是使用scan来进行查询。scan可以分批查。

redis禁用危险命令有哪些?

keys * 虽然其模糊匹配功能使用非常方便也很强大,在小数据量情况下使用没什么问题,数据量大会导致 Redis 锁住及 CPU 飙升,在生产环境建议禁用或者重命名! flushdb 删除 Redis 中当前所在数据库中的所有记录,并且此命令从不会执行失败 flushall 删除 Redis 中所有数据库中的所有记录,不只是当前所在数据库,并且此命令从不会执行失败。 config 客户端可修改 Redis 配置。

Redis连接时的connect与pconnect的区别是什么?

connect:脚本结束之后连接就释放了。 pconnect:脚本结束之后连接不释放,连接保持在php-fpm进程中。每个php-fpm进程占用一个连接,当php-fpm进程结束时会释放掉 ; 所以使用pconnect代替connect,可以减少频繁建立redis连接的消耗。

lua 脚本的作用是什么?

Redis 脚本使用 Lua 解释器来执行脚本。 Redis 2.6 版本通过内嵌支持 Lua 环境。执行脚本的常用命令为EVAL。

相比Redis事务来说,Lua脚本有以下优点

减少网络开销: 不使用 Lua 的代码需要向 Redis 发送多次请求,而脚本只需一次即可,减少网络传输; 原子操作:Redis 将整个脚本作为一个原子执行,无需担心并发,也就无需事务; 复用:脚本会永久保存 Redis 中,其他客户端可继续使用 分布式限流最关键的是要将限流服务做成原子化,而解决方案可以使用redis+lua或者nginx+lua技术进行实现,通过这两种技术可以实现的高并发和高性能。 首先我们来使用redis+lua实现时间窗内某个接口的请求数限流,实现了该功能后可以改造为限流总并发/请求数和限制总资源数。Lua本身就是一种编程语言,也可以使用它实现复杂的令牌桶或漏桶算法。 因操作是在一个lua脚本中(相当于原子操作),又因Redis是单线程模型,因此是线程安全的。 扩展:https://www.runoob.com/redis/redis-scripting.html

redis队列解决抢购高并发?

在程序跟数据库之前呢我们可以利用redis队列做一个缓冲机制,让所有用户的请求进行排队,禀行先进先出的原则(redis中的lpush和rpop), lpush程序是把用户的请求压入redis队列,然后用rpop做一个守护进程来取队列中的数据,按规定的抢购名额写好, 把所有抢购成功的用户写入redis并且生成订单,在lpush程序中查看中奖的用户并且给用户及时提醒抢购结果!

集合命令的实现方法

命令 intset 编码的实现方法 hashtable 编码的实现方法 SADD 调用 intsetAdd 函数,将所有新元素添加到整数集合里面 调用 dictAdd,以新元素为键,NULL 为值,将键值对添加到字典里面 SCARD 调用 intsetLen 函数,返回整数集合所包含的元素数量,这个数量就是集合对象所包含的元素数量 调用 dictSize 函数,返回字典所包含的键值对数量,这个数量就是集合对象所包含的元素数量 SISMEMBER 调用 intsetFind 函数,在整数集合中查找给定的元素,如果找到了元素存在于集合,没找到则说明元素不存在集合 调用 dictFind 函数,在字典的键中查找给定的元素,如果找到了说明元素存在于集合,没找到则说明元素不存在于集合 SMEMBERS 遍历整个整数集合,调用 inisetGet 函数返回集合元素 遍历整个字典,使用 dictGetKey 函数返回字典的键作为集合元素 SRANDMEMBER 调用 intsetRandom 函数,从整数集合中随机返回一个元素 调用 dictGetRandomKey 函数,从字典中随机返回一个字典键 SPOP 调用 intsetRandom 函数,从整数集合中随机取出一个元素,再将这个随机元素返回给客户端之后,调用 intsetRemove 函数,将随机元素从整数集合中删除掉 调用 dictGetRandomKey 函数,从字典中随机取出一个字典键,在将这个随机字典键的值返回给客户端之后,调用 dictDelete 函数,从字典中删除随机字典键所对应的键值对 SREM 调用 intsetRemove 函数,从整数集合中删除所有给定的元素 调用 dictDelete 函数,从字典中删除所有键为给定元素的键值对

有序集合命令的实现方法

命令 ziplist 编码的实现方法 zset 编码的实现方法 ZADD 调用 ziplistInsert 函数,将成员和分值作为两个节点分别插入到压缩列表 先调用 zslInsert 函数,将新元素添加到跳跃表,然后调用 dictAdd 函数,将新元素关联到字典 ZCARD 调用 ziplistLen 函数,获得压缩列表包含节点的数量,将这个数量除以2得出集合元素的数量 访问跳跃表数据结构的 length 属性,直接访问集合元素的数量 ZCOUND 遍历压缩列表,统计分值在给定范围内的节点的数量 遍历跳跃表,统计分值在给定范围内的节点的数量 ZRANGE 从表头向表尾遍历压缩列表,返回给定索引范围内的所有元素 从表头向表尾遍历跳跃表,返回给定索引范围内的所有元素 ZREVRANGE 表尾向表头遍历压缩列表,返回给定索引范围内的所有元素 从表尾向表头遍历跳跃表,返回给定索引范围的所有元素 ZRANK 从表头向表尾遍历压缩列表,查找给定的成员,沿途记录经过节点的数量,当找到给定成员之后,沿途节点的数量就是该成员所对应元素的排名 从表头向表尾遍历跳跃表,查找给定的成员,沿途记录经过节点的数量,当找到给定成员之后,沿途节点的数量就是该成员所对应元素的排名 ZREVRANK 从表尾向表头遍历压缩列表,查找给定的成员,沿途记录经过节点的数量,当找到给定成员之后,沿途节点的数量就是该成员所对应元素的排名 从表尾向表头遍历跳跃表,查找给定的成员,沿途纪录经过节点的数量,当找到给定成员之后,沿途节点的数量就是该成员所对应元素的排名 ZREM 遍历压缩列表,删除所有包含给定成员的节点,以及被删除成员节点旁边的分值节点 遍历跳跃表,删除所有包含了给定成员的跳跃表节点。并在字典中解除被删除元素的成员和分值关联 ZSCORE 遍历压缩列表,查找包含了给定成员的节点,然后取出成员节点旁边的分值节点保存的元素分值

脑裂问题是啥?

当客户端无法取到锁时,应该在一个随机延迟后重试,防止多个客户端在同时抢夺同一资源的锁(这样会导致脑裂,没有人会取到锁)。同样,客户端取得大部分Redis实例锁所花费的时间越短,脑裂出现的概率就会越低(必要的重试),所以,理想情况一下,客户端应该同时(并发地)向所有Redis发送SET命令。 需要强调,当客户端从大多数Redis实例获取锁失败时,应该尽快地释放(部分)已经成功取到的锁,这样其他的客户端就不必非得等到锁过完“有效时间”才能取到(然而,如果已经存在网络分裂,客户端已经无法和Redis实例通信,此时就只能等待key的自动释放了,等于被惩罚了)。 原子执行的命令(multi + exec)

MULTI OK INCR foo QUEUED INCR bar QUEUED EXEC

  1. (integer) 1
  2. (integer) 1

redis set 和get为什么这么快?

就是hash计算 redis如何实现ACID? redis 可以实现原子性,一致性,隔离性。但是不能保证持久性。 原子性,multi会先把命令放到队列里面,然后exec执行命令。

#开启事务 127.0.0.1:6379> MULTI OK #将a:stock减1, 127.0.0.1:6379> DECR a:stock QUEUED #将b:stock减1 127.0.0.1:6379> DECR b:stock QUEUED #实际执行事务 127.0.0.1:6379> EXEC

  1. (integer) 4
  2. (integer) 9

命令入队时就报错,会放弃事务执行,保证原子性; 命令入队时没报错,实际执行时报错,不保证原子性; EXEC 命令执行时实例故障,如果开启了 AOF 日志,可以保证原子性。redis-check-aof检查aof文件,可以把已执行的事务操作从aof文件中删除。 一致性 隔离性 watch机制。

跳跃表的时间复杂度是什么?

一般是O(logn) 最差是 O(n)

一致性哈希是什么?

一致性哈希用于解决分布式缓存系统中的数据选择节点存储问题和数据选择节点读取问题以及在增删节点后减少数据缓存的消失范畴,防止雪崩的发生。 类似于mysql的分库分表策略,优点是可以动态的添加删除redis节点,不会造成缓存雪崩,可以同时既当缓存,又当数据库使用。

哈希槽是什么?

Redis 集群没有使用一致性hash, 而是引入了哈希槽的概念。 哈希槽是在redis cluster集群方案中采用的,redis cluster集群没有采用一致性哈希方案,而是采用数据分片中的哈希槽来进行数据存储与读取的。 Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。 Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽。这种结构很容易添加或者删除节点,并且无论是添加删除或者修改某一个节点,都不会造成集群不可用的状态。 使用哈希槽的好处就在于可以方便的添加或移除节点。 当需要增加节点时,只需要把其他节点的某些哈希槽挪到新节点就可以了; 当需要移除节点时,只需要把移除节点上的哈希槽挪到其他节点就行了; 在这一点上,我们以后新增或移除节点的时候不用先停掉所有的 redis 服务。 扩展:https://segmentfault.com/a/1190000022718948 集群情况下,节点较少时数据分布不均匀怎么办? 对于分布式系统来说,整个集群的存储容量和处理能力,往往取决于集群中容量最大或响应最慢的节点。因此在前期进行系统设计和容量规划时,应尽可能保证数据均衡。但是,在生产环境的业务系统中,由于各方面的原因,数据倾斜的现象还是比较常见的。Redis Cluster也不例外,究其原因主要包括两个:一个是不同分片间key数量不均匀,另一个是某分片存在bigkey;接下来我们看看,在腾讯云数据库redis中,如何及时发现和解决分片数据不均匀的问题。

对于分片间key数量不均匀,导致数据倾斜问题,可考虑以下方案(可能性小):

解决方案: (1)垂直扩容:扩容单分片内存容量(不推荐) (2)水平扩容:扩容分片数,以把key打散到不同分片(推荐) 对于某分片存在bigkey,导致数据倾斜问题,可考虑以下方案(可能性大): (1)垂直扩容:扩容单分片内存容量(不推荐) (2)对bigkey进行改造,拆分成多个key打散(推荐)

Linux 基础

查看系统信息、内存信息、磁盘信息、负载信息、路由信息、端口信息、进程、登录用户、关机、重启、系统时间、用户管理、文件权限、压缩解压 Linux 目录结构 / ├── bin #存放二进制可执行文件,常用命令一般都在这里 ├── boot #存放用于系统引导时使用的各种文件 ├── dev #用于存放设备文件 ├── etc #存放系统管理和配置文件 ├── home #存放所有用户文件的根目录 ├── lib #存放着和系统运行相关的库文件 ├── media #linux 系统会自动识别一些设备,当识别后,linux 会把识别的设备挂载到这个目录下 ├── mnt #用户临时挂载其他的文件系统 ├── opt #额外安装的可选应用程序包所放置的位置 ├── proc #虚拟文件系统目录,是系统内存的映射。可直接访问这个目录来获取系统信息 ├── root #超级用户的主目录 ├── run #是一个临时文件系统,存储系统启动以来的信息 ├── sbin #存放二进制可执行文件,只有 root 才能访问 ├── srv #该目录存放一些服务启动之后需要提取的数据 ├── sys #存放内核相关文件 ├── tmp #用于存放各种临时文件,是公用的临时文件存储点 ├── usr #用于存放系统应用程序 └── var #用于存放运行时需要改变数据的文件,比如服务的日志文件

文件描述符

文件描述符是一个非负的索引,一般从3开始(0,1,2均被使用),指向内核中的“文件记录表”,内核为进程要使用的文件维护一个“文件记录表”。 • 进程需要打开或新建文件时,内核向进程返回一个文件描述符;

• 进程需要读写文件时,也需要将文件描述符作为参数传递给函数;

• Linux下所有对设备和文件的操作都由文件描述符完成。

命令与文件查找有哪些命令?

which-寻找可执行文件 [root@localhost ~]# which php /usr/bin/php

whereis-特定目录寻找 [root@localhost ~]# whereis php php: /usr/bin/php /usr/lib64/php /etc/php.d /etc/php.ini /usr/include/php /usr/share/php /usr/share/man/man1/php.1.gz

find-直接搜索硬盘 [root@localhost ~]# find / -name php-fpm /run/php-fpm /etc/sysconfig/php-fpm /etc/logrotate.d/php-fpm /var/log/php-fpm /usr/sbin/php-fpm

数据流怎么分类?

数据流分为三类:标准输入(stdin)、标准输出(stdout)、标准错误输出(stderr) /dev/null:是一个特殊的设备文件,这个文件接收到的任何数据都会被丢弃。因此,null 这个设备通常也被成为位桶(bit bucket)或黑洞 计划任务 代表意义 分钟 小时 日期 月份 星期 指令 数字范围 0-59 0-23 1-31 1-12 0-7 command 特殊符号 意义 示例

  • 表示任何时刻 * , 表示分隔时段 0 3,6 * * * command(3:00与6:00)
  • 表示一段时间范围 20 8-12 * * * command(8:20~12:20) /n 每隔 n 段时间 */5 * * * * command(每五分钟进行一次) I/O模型 同步阻塞IO:在内核等待数据和将数据复制到进程地址空间的两个过程,除了等待啥也不做。及时返回数据,无延迟。 同步非阻塞IO:在内核等待数据的阶段,进程可以轮询(瞅瞅它准备好数据了没),后一阶段等待。此外,在轮询之外的时间可以干其他活儿了,但是这样会拉长此进程的时延(也许人家在你轮询之前准备好了)。 异步IO:异步模式时被动接收消息,如通过回调、通知、状态等方式被动获取;不是顺序执行。异步非阻塞IO中,用户进程进行系统调用后,无论内核是否准备好都会返回响应,进程可以去做别的事情,内核复制好数据之后会通知进程。 信号驱动IO:建立SIGIO信号处理函数,数据准备好后进程会收到SIGIO信号。可以在信号处理函数中调用IO操作函数处理数据。 IO多路复用: 多路:多个连接,复用:一个或少量线程。即使用一个或少量的线程去处理多个连接。 不停地查看多个任务的完成状态,只要有任何一个任

标签: 0aa1压力变送器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台