2020个人面试题汇总
MySQL 如何优化
当 MySQL 单表记录数过大时,增删改查性能都会急剧下降,可以参考以下步骤来优化:
单表优化、字段、索引、查询SQL、存储引擎、升级硬件、读写分离、缓存、分表分区、使用NoSQL等。
单表优化——除非单表数据未来会一直不断上涨,否则不要一开始就考虑拆分,拆分会带来逻辑、部署、运维的各种复杂度,一般以整型值为主的表在千万级以下,字符串为主的表在五百万以下是没有太大问题的。而事实上很多时候 MySQL 单表的性能依然有不少优化空间,甚至能正常支撑千万级以上的数据量。
字段
- 尽量使用 TINYINT、SMALLINT、MEDIUM_INT 作为整数类型而非 INT,如果非负则加上 UNSIGNED
- VARCHAR 的长度只分配真正需要的空间
- 使用枚举或整数代替字符串类型
- 尽量使用 TIMESTAMP 而非 DATETIME
- 单表不要有太多字段,建议在
20
以内 - 避免使用 NULL 字段,很难查询优化且占用额外索引空间
- 用整型来存IP(PHP::
ip2long
,long2ip
;MySQL:INET_ATON
,INET_NTOA
)
索引
- 索引并不是越多越好,要根据查询有针对性的创建。考虑在
WHERE
和ORDER BY
命令上涉及的列建立索引,可根据 EXPLAIN 来查看是否用了索引还是全表扫描 - 不用外键,由程序保证约束
- 尽量不用 UNIQUE,由程序保证约束
- 使用多列索引时主意顺序和查询条件保持一致,同时删除不必要的单列索引
- 索引并不是越多越好,要根据查询有针对性的创建。考虑在
查询SQL
- 可通过开启慢查询日志来找出较慢的SQL,针对优化
- 避免 sql 中做运算操作
- sql 语句尽可能简单:一条 sql 只能在一个 cpu 运算;大语句拆小语句,减少锁时间;一条大 sql 可以堵死整个库
- 尽量不用
SELECT *
- OR 改写成 IN:OR 的效率是
n
级别,IN 的效率是log(n)
级别,IN 的个数建议控制在 200 以内 - 不用函数和触发器,在应用程序实现
- 少用JOIN
- 避免模糊查询
- 尽量避免在 WHERE 子句中使用
!=
或<>
操作符,否则将引擎放弃使用索引而进行全表扫描 - 对于连续数值,使用 **BETWEEN **不用 **IN **:
SELECT id FROM t WHERE num BETWEEN 1 AND 5
- 列表数据不要拿全表,要使用LIMIT来分页,每页数量也不要太大
存储引擎
目前广泛使用的是 MyISAM 和 InnoDB 两种引擎。
MyISAM 特点:
- 不支持行锁,读取时对需要读到的所有表加锁,写入时则对表加排它锁
- 不支持事务
- 不支持外键
- 不支持崩溃后的安全恢复
- 在表有读取查询的同时,支持往表中插入新纪录
- 支持 BLOB 和 TEXT 的前 500 个字符索引,支持全文索引
- 支持延迟更新索引,极大提升写入性能
- 对于不会进行修改的表,支持压缩表,极大减少磁盘空间占用
InnoDB 特点:
- 支持行锁,采用 MVCC(多版本并发控制) 来支持高并发
- 支持事务
- 支持外键
- 支持崩溃后的安全恢复
- 不支持全文索引
总体来讲,MyISAM 适合 SELECT 密集型的表,而 InnoDB 适合 INSERT 和 UPDATE 密集型的表。
升级硬件
软件不够,硬件来凑
读写分离
是目前常用的优化,从库读主库写,一般不要采用双主或多主引入很多复杂性,尽量采用其他方案来提高性能。同时目前很多拆分的解决方案同时也兼顾考虑了读写分离。
缓存
- MySQL 内部
- 应用服务层,及通过代码对大量相同查询做缓存处理
- Web层:针对 web 页面做缓存
- 浏览器客户端:用户端的缓存
分表
在可提前遇见某张表将来会有大量数据需要入表,可以通过一定规则将数据平均存储到多张表中,查询也从分表中查询。既可以提高数据存储量,也可以提高查询效率。
表分区
MySQL 在 5.1 版引入的分区是一种简单的水平拆分,用户需要在建表的时候加上分区参数,对应用是透明的无需修改代码。
对用户来说,分区表是一个独立的逻辑表,但是底层由多个物理子表组成,实现分区的代码实际上是通过对一组底层表的对象封装,但对 SQL 层来说是一个完全封装底层的黑盒子。MySQL 实现分区的方式也意味着索引也是按照分区的子表定义,没有全局索引。
可以通过
EXPLAIN PARTITIONS
来查看某条 SQL 语句会落在那些分区上,从而进行 SQL 优化NoSQL
结合 Redis、Memcached 等我不工具提升性能。
MySQL 如何确定命中索引
在项目开发中 SQL 是必不可少的,表索也一样。这些 SQL 的运行性能不知道吗?有多少是命中了索引的?命中哪个索引?索引中有哪个是无效索引?这些无效索引是否会影响系统的性能?带着这些问题我们一起来学习一下。
MySql 中是通过 Explain 命令来分析低效 SQL 的执行计划。命令的使用很简单.
示例 explain select * from user
执行结果:
1 |
|
执行结果每一列的说明:
select_type : 查询类型,常见的值:
SIMPLE
:简单表,不使用表连接或子查询。PRIMARY
: 主查询,外层的查询。UNION
第二个或者后面的查询语句。SUBQUERY
: 子查询中的第一个select
table :输出结果的表
type : 表示MySql在表中找到所需行的方式,或者叫访问类型。常见的类型:
ALL、index、range、ref、eq_ref、const,system、NULL。
从左到右,性能由最差到最好。
possible_keys : 可能使用的索引列表.
key : 实现执行使用索引列表
key_len : 索引的长度
ref : 显示使用哪个列或常数与 key 一起从表中选择行。
row : 执行查询的行数,简单且重要,数值越大越不好,说明没有用好索引
Extra: 该列包含 MySQ L解决查询的详细信息。
详解查看: MySql优化-你的SQL命中索引了吗
Laravel 和 ThinkPHP
ThinkPHP简单、快速,基于MVC和面向对象,易用性较高,是一款简洁实用的轻量级框架。
Lavavel一直秉承着优雅的原则,很好的支持了composer,实现了更丰富的扩展,社区文档活跃,相较于TP,Lavavel更庞大,安全性也更高,更适合开发大中型项目,被称为“巨匠型开发框架”。
Laravel 提供了
.env
文件存放公共配置信息,在经常切换工作地点、服务器更加灵活方便。Laravel 在表单提交的时候会有 csrf 跨站请求伪造验证,Tp5则没有。
Laravel 通过
make:migration
创建表迁移文件,使得表迁移更加方便。Laravel 模板语法功能丰富,强大
Laravel 使用范围广,热度高,文档齐全;ThinkPHP 主要服务在国内。
Laravel亮点
Laravel 框架的设计思想比较先进,非常适合应用各种开发模式,作为一个框架,它为你准备好了一切。composer 是 php 的未来,没有 composer,php 肯定要走向没落。 laravel 框架最大的特点和优秀之处就是集合了 php 比较新的特性,以及各种各样的设计模式,、Ioc模式、依赖注入等。
特点
- 强大的 router路由功能:用简单的回调函数就可以调用,快速绑定 controller 和 router
- artisan:命令行工具,很多手动的工作都自动化
- 可继承的模,简化 view 的开发和管理
- blade模板:渲染速度更快
- ORM 操作数据库
- migration:管理数据库和版本控制
- 测试功能也很强大
- composer也是亮点
- laravel 框架引入了门面、依赖注入、Ioc模式、以及各种各样的设计模式等
为什么使用 Laravel
使用了大量设计模式以及 PHP 的新特性,框架完全符合设计模式的五大基本原则(面向对象设计模式有5大基本原则:单一职责原则、开发封闭原则、依赖倒置原则、接口隔离原则、Liskov(里是替换)原则。),模块之间耦合度很低,服务容器可以方便的扩展框架功能以及编写测试。
能快速开发出功能,自带各种方便的服务,比如数据验证、队列、缓存、数据迁移、测试、artisan 命令行等等,还有强大的 ORM 。
PHP7新特性
允许标量类型声明
函数/方法中的参数,是可以加一个类型声明的(字符串(string), 整数 (int), 浮点数 (float), 以及布尔值 (bool)等)
返回值类型声明
PHP 7 增加了对返回类型声明的支持。 类似于参数类型声明,返回类型声明指明了函数返回值的类型。可用的类型与参数声明中可用的类型相同。
null合并运算符
??
如果变量存在且值不为**
NULL
**, 它就会返回自身的值,否则返回它的第二个操作数。太空船操作符
太空船操作符用于比较两个表达式。当$a小于、等于或大于$b时它分别返回-1、0或1。
define允许定义常量数组
匿名类
现在支持通过new class 来实例化一个匿名类,这可以用来替代一些“用后即焚”的完整类定义。
Unicode codepoint 转译语法
这接受一个以16进制形式的 Unicode codepoint,并打印出一个双引号或heredoc包围的 UTF-8 编码格式的字符串。 可以接受任何有效的 codepoint,并且开头的 0 是可以省略的。
use分组命名空间
新增整数整除的函数intdiv()
新加的函数 intdiv() 用来进行 整数的除法运算。
新增的随机函数
MySQL索引类型
普通索引、主键索引、唯一索引、组合索引、全文索引
MySQL事务隔离级别
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read-uncommitted) | 是 | 是 | 是 |
不可重复读(read-committed) | 否 | 是 | 是 |
可重复读(repeatable-read) | 否 | 否 | 是 |
串行化(serializable) | 否 | 否 | 否 |
- 1、事务隔离级别为读提交时,写数据只会锁住相应的行
- 2、事务隔离级别为可重复读时,如果检索条件有索引(包括主键索引)的时候,默认加锁方式是next-key 锁;如果检索条件没有索引,更新数据时会锁住整张表。一个间隙被事务加了锁,其他事务是不能在这个间隙插入记录的,这样可以防止幻读。
- 3、事务隔离级别为串行化时,读写数据都会锁住整张表
- 4、隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。
Linux命令查找出日志文件中访问量最大的10个ip
1 |
|
每一步命令解释:
cat ip.txt
:将 ip.txt 文件内容输出到终端|
:通过管道符|将左边命令输出作为右边命令输入(后面|功能类似)awk -F" " '{print $2}'
-F
: 指定输入文件拆分分隔符 -F” “: 以空格分隔{print $2}
: 分隔后每一行就分成了时间戳和 ip 两个单元 $1 指时间 $2 指 ip, print $2 即输出 ip。
sort
: 对输出ip进行排序uniq -c
检查及删除文本文件中重复出现的行列 -c 或 –count 在每列旁边显示该行重复出现的次数。此时输出的数据格式为 出现次数 ip。sort -nrt " "
对输出结果排序。 -n : 依照数值的大小排序 -r : 以相反的顺序来排序 -t : <分隔字符> 指定排序时所用的栏位分隔字符。接着继续用 awk 将数据第二列 ip 输出
head -10 取前十条数据
原文链接:https://blog.csdn.net/qq_33722172/java/article/details/84257910
MySQL 最左原则原理
什么是最左匹配原则
最左优先,以最左边的为起点任何连续的索引都能匹配上。同时遇到范围查询(>、<、between、like就会停止匹配。
最左匹配原则的原理
最左匹配原则都是针对联合索引来说的。索引的底层是一颗 B+树
,那么联合索引当然还是一颗B+树,只不过联合索引的健值数量不是一个,而是多个。构建一颗 B+树
只能根据一个值来构建,因此数据库依据联合索引最左的字段来构建 B+树
。
MySQL在查询主键信息,当表中存在其他索引时,会命中其他索引而非主键索引
1 |
|
Golang 特点, goroutine 和 channel 如何配合工作的
Golang 特点
强类型静态编译型语言。
- 更丰富的内置类型
- 函数多返回值
- 错误处理:defer、panic、recover
- 匿名函数和闭包
- 类型和接口
- 并发编程
- 反射
- 语言交互性
- 自动垃圾回收
goroutine
goroutine 是 go 语言中最为 NB 的设计,也是其魅力所在,goroutine 的本质是协程,是实现并行计算的核心。goroutine 使用方式非常的简单,只需使用 go
关键字即可启动一个协程,并且它是处于异步方式运行,你不需要等它运行完成以后在执行以后的代码。
1 |
|
Go 语言最大的特色就是从语言层面支持并发(Goroutine),Goroutine 是 Go中最基本的执行单元。事实上每一个 Go 程序至少有一个 Goroutine:主 Goroutine。当程序启动时,它会自动创建。
goroutine内部原理
先理解几个概念:
并发:一个 cpu 上能同时执行多项任务,在很短时间内,cpu来回切换任务执行。
并行:当系统有多个CPU时,每个CPU同一时刻都运行任务,互不抢占自己所在的CPU资源,同时进行,称为并行。
进程:cpu在切换程序的时候,如果不保存上一个程序的状态(也就是我们常说的context–上下文),直接切换下一个程序,就会丢失上一个程序的一系列状态,于是引入了进程这个概念,用以划分好程序运行时所需要的资源。因此进程就是一个程序运行时候的所需要的基本资源单位(也可以说是程序运行的一个实体)。
线程:有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆(heap, 一般由程序员分配释放) 栈(stack,由编译器自动分配释放 ,存放函数的参数值,局部变量的值等)组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。
协程:又称微线程与子例程(或者称为函数)一样,协程(coroutine)也是一种程序组件。相对子例程而言,协程更为一般和灵活,但在实践中使用没有子例程那样广泛。
和线程类似,共享堆,不共享栈,协程的切换一般由程序员在代码中显式控制。它避免了上下文切换的额外耗费,兼顾了多线程的优点,简化了高并发程序的复杂。
Goroutine和其他语言的协程(coroutine)在使用方式上类似,但从字面意义上来看不同(一个是Goroutine,一个是coroutine),再就是协程是一种协作任务控制机制,在最简单的意义上,协程不是并发的,而Goroutine支持并发的。因此Goroutine可以理解为一种Go语言的协程。同时它可以运行在一个或多个线程上。
GO并发的实现原理
Go实现了两种并发形式。第一种是大家普遍认知的:多线程共享内存。其实就是Java或者C++等语言中的多线程开发。另外一种是Go语言特有的,也是Go语言推荐的:CSP(communicating sequential processes)并发模型。
CSP并发模型是在1970年左右提出的概念,属于比较新的概念,不同于传统的多线程通过共享内存来通信,CSP讲究的是“以通信的方式来共享内存”。
请记住下面这句话:
DO NOT COMMUNICATE BY SHARING MEMORY; INSTEAD, SHARE MEMORY BY COMMUNICATING.
“不要以共享内存的方式来通信,相反,要通过通信来共享内存。”
普通的线程并发模型,就是像Java、C++、或者Python,他们线程间通信都是通过共享内存的方式来进行的。非常典型的方式就是,在访问共享数据(例如数组、Map、或者某个结构体或对象)的时候,通过锁来访问,因此,在很多时候,衍生出一种方便操作的数据结构,叫做“线程安全的数据结构”。例如Java提供的包”java.util.concurrent”中的数据结构。Go中也实现了传统的线程并发模型。
Go的CSP并发模型,是通过goroutine
和channel
来实现的。
goroutine
是Go语言中并发的执行单位。有点抽象,其实就是和传统概念上的”线程“类似,可以理解为”线程“。channel
是Go语言中各个并发结构体(goroutine
)之前的通信机制。 通俗的讲,就是各个goroutine
之间通信的”管道“,有点类似于Linux中的管道。
生成一个goroutine
的方式非常的简单:Go一下,就生成了。
1 |
|
通信机制channel
也很方便,传数据用channel <- data
,取数据用<-channel
。
在通信过程中,传数据channel <- data
和取数据<-channel
必然会成对出现,因为这边传,那边取,两个goroutine
之间才会实现通信。
而且不管传还是取,必阻塞,直到另外的goroutine
传或者取为止。
示例如下:
1 |
|
注意 main()本身也是运行了一个goroutine。
messages:= make(chan int) 这样就声明了一个阻塞式的无缓冲的通道
chan 是关键字 代表我要创建一个通道
channel
channel 俗称管道,用于数据传递或数据共享,其本质是一个先进先出的队列,使用 goroutine+channel
进行数据通讯简单高效,同时也线程安全,多个 goroutine 可同时修改一个 channel,不需要加锁。
channel可分为三种类型:
只读channel:只能读channel里面数据,不可写入
只写channel:只能写数据,不可读
一般channel:可读可写
channel使用
定义和声明
1 |
|
读写数据需要注意的是:
- 管道如果未关闭,在读取超时会则会引发
deadlock
异常 - 管道如果关闭进行写入数据会
pannic
- 当管道中没有数据时候再行读取或读取到默认值,如 int 类型默认值是 0
goroutine 和 channel 如何配合工作
goroutine 本质上是协程,可以理解为不受内核调度,而受 go 调度器管理的线程。goroutine 之间可以通过channel 进行通信或者说是数据共享,当然你也可以使用全局变量来进行数据共享。
go语言之行–golang核武器goroutine调度原理、channel详解
CI 和 Laravel 区别、优缺点,Laravel 臃肿如何优化
CodeIgniter:
优点:
.框架简单,容易上手,学习成本低,文档详细
配置简单,全部的配置使用PHP脚本来配置,执行效率高
快速简洁,代码不多,执行性能高
自带了很多简单好用的library,框架适合小型应用
具有基本的路由功能,能够进行一定程度的路由
数据库层封装的不错,具有基本的MVC功能
缺点:
- 内部结构过于混乱,虽然简单易用,但缺乏扩展能力
- 框架略显简单,只能够满足小型应用,略微不太能够满足中型应用需要
Laravel:
优点:
- laravel的设计思想是很先进的,非常适合应用各种开发模式
- 支持composer包管理工具,扩展方便
- 集合了php 比较新的特性,以及各种各样的设计模式,Ioc 容器,依赖注入、门面、契约。测试功能等
缺点:
- 基于组件式的框架,所以比较臃肿
Laravel优化
配置文件缓存
1
php artisan config:cache # php artisan config:clear 清除 config 缓存
route 缓存
1
php artisan route:cache # php artisan route:clear 清除 route 缓存
类映射加载优化
1
php artisan optimize --force # php artisan clear-compiled 此命令会删除上面 optimize 生成的两个文件
使用redis/memcached来储存session会话
在 config/session.php 里修改储存方式
'driver' => 'redis',
使用专业的缓存驱动器
「缓存」是提高应用程序运行效率的法宝之一,默认缓存驱动是
file
文件缓存,建议切换到专业的缓存系统,如 Redis 或者 Memcached,不建议使用数据库缓存。可以再配置文件 config/cache.php 里修改:
'default' => 'reids',
composer 工作原理,CI 如何引入 composer
https://www.php.cn/tool/composer/428240.html
什么是Composer?**
Composer 是 PHP 的一个依赖管理工具,简单的说就是我们的项目通常会使用其它代码库,这时仅仅是在项目中申明依赖哪些代码库,默认情况下它不会在全局安装任何东西。
Composer的意义?
对于现代语言而言,依赖管理工具基本上是标配。Java 有 Maven,Python 有 pip,Ruby 有 gem,Nodejs 有 npm。PHP 的则是 PEAR,不过 PEAR 坑不少:依赖处理容易出问题,配置非常复杂,难用的命令行接口等等。
正是因为Composer的出现,解决了项目依赖的问题,并使PHP开发工作因此变得如同堆积木一般。
Composer工作原理
Composer又是如何工作的呢,举个例子当我们去安装一个软件的时候,一般是通过app store 去安装。当我们开发PHP项目的时候,也会面临同样的问题。比如我们需要一个工具记录业务log,那这样我们是不是可以通过一个php的应用商店来下载我们需要的工具。
Packagist 是 Composer 的默认的开发包仓库。你可以将自己的安装包提交到 packagist,你在自己的 VCS (源码管理软件,比如 Github)仓库中新建了 tag 或更新了代码,packagist 都会自动构建一个新的开发包。这就是 packagist 目前的运作方式,packagist 允许直接上传开发包,发布自己的包。
CI 如何引入 composer
新建
composer.json
文件,内容大概是1
2
3
4
5
6
7
8
9
10
11
12{
"require" : {
"php" : ">= 5.6.7",
"filp/whoops" : "*"
},
"repositories": { # 切换镜像源
"packagist": {
"type": "composer",
"url": "https://packagist.phpcomposer.com"
}
}
}在
index.php
中引入composer库1
2//载入composer
require_once './vendor/autoload.php';
ORM 如何实现链式操作
1 |
|
原理很简单,在每个方法返回 $this
Object 即可。
一个 Class 的 __construct 方法属性为 private,外部如何访问该类的方法
题目要说的其实就是 PHP 单例模式的实现:
1 |
|
1 |
|
PHP 反射
mysql中的回表查询与索引覆盖
nginx反向代理配置
1 |
|
nginx负载均衡配置
1 |
|
<?php echo count(strlen("http://www.php.net")); ?>
的执行结果是?
执行结果:
1 |
|
注:*count
— 计算数组中的单元数目,或对象中的属性个数*,即 count
变量只接受数组或者对象,上面给的是数字,所以报错。
使用 list 函数需要注意什么?
list — 把数组中的值赋给一组变量
像 array() 一样,这不是真正的函数,而是语言结构。 list() 可以在单次操作内就为一组变量赋值。
list() 仅能用于数字索引的数组,并假定数字索引从 0 开始。
echo(),print(),print_r()的区别?
echo
是一个语言结构,输出一个或多个字符串;
print()
实际上不是一个函数(它是一个语言结构),因此你可以不必使用圆括号来括起它的参数列表,它输出一个字符串;
print_r ()
是一个函数,打印变量的信息,基本类型,数组,对象。
PHP5底层原理之垃圾回收机制
如何在命令行下运行PHP脚本(写出两种方法),如何向PHP脚本传入参数?
方法:
php
+ 脚本文件php -r 'PHP脚本'
传参:
直接在命令后面以空格形式接一个或多个参数即可,例如:
1 |
|
1 |
|
PHP 的 strtolower 和 strtoupper 函数在安装非中文系统的服务器下可能导致将汉字转换为乱码,请写两个替代函数实现兼容 Unicode 文字的字符串大小写转换。
1 |
|
注:在php中,不同编码下不相同,在GBK/GB2312编码下一个中文占2个字符,UTF-8/unicode编码下一个中文占3个字符;
PHP 的 is_writable 无法准确判断一个文件或目录是否准确可写,请写一个函数判断文件会目录是否绝对可写
原文链接:https://blog.csdn.net/u013474436/java/article/details/50674040
is_writable bug存在两个方面,
1、在 windowns 中,当文件只有只读属性时,is_writeable()
函数才返回 false,当返回 true 时,该文件不一定是可写的。
2、在 Unix 中,当 php 配置文件中开启 safe_mode
时 (safe_mode=on),is_writeable()
同样不可用。
读取配置文件是否 safe_mode
是否开启。
如果是目录,在目录中新建文件并通过打开文件来判断;
如果是文件,可以通过打开文件(fopen),来测试文件是否可写。
1 |
|
如何解决Redis雪崩、穿透、并发等5大难题
原文链接:https://blog.csdn.net/Chaoren666/java/article/details/89953969
缓存雪崩
数据未加载到缓存中,或者缓存同一时间大面积的失效,从而导致所有请求都去查数据库,导致数据库CPU和内存负载过高,甚至宕机。
比如一个雪崩的简单过程:
redis集群大面积故障
缓存失效,但依然大量请求访问缓存服务 redis
redis大量失效后,大量请求转向到 mysql 数据库
mysql的调用量暴增,很快就扛不住了,甚至直接宕机
由于大量的应用服务依赖mysql和redis的服务,这个时候很快会演变成各服务器集群的雪崩,最后网站彻底崩溃。
如何预防缓存雪崩:
- 缓存的高可用性
缓存层设计成高可用,防止缓存大面积故障。即使个别节点、个别机器、甚至是机房宕掉,依然可以提供服务,例如 Redis Sentinel(哨兵) 和 Redis Cluster(集群) 都实现了高可用。
- 缓存降级
可以利用 ehcache 等本地缓存(暂时支持),但主要还是对源服务访问进行限流、资源隔离(熔断)、降级等。
当访问量剧增、服务出现问题仍然需要保证服务还是可用的。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级,这里会涉及到运维的配合。
降级的最终目的是保证核心服务可用,即使是有损的。
比如推荐服务中,很多都是个性化的需求,假如个性化需求不能提供服务了,可以降级补充热点数据,不至于造成前端页面是个大空白。
在进行降级之前要对系统进行梳理,比如:哪些业务是核心(必须保证),哪些业务可以容许暂时不提供服务(利用静态页面替换)等,以及配合服务器核心指标,来后设置整体预案,比如:
(1)一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自动降级;
(2)警告:有些服务在一段时间内成功率有波动(如在95~100%之间),可以自动降级或人工降级,并发送告警;
(3)错误:比如可用率低于90%,或者数据库连接池被打爆了,或者访问量突然猛增到系统能承受的最大阀值,此时可以根据情况自动降级或者人工降级;
(4)严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级。
- Redis备份和快速预热
1)Redis数据备份和恢复
2)快速缓存预热
4.提前演练
最后,建议还是在项目上线前,演练缓存层宕掉后,应用以及后端的负载情况以及可能出现的问题,对高可用提前预演,提前发现问题。
缓存穿透
缓存穿透是指查询一个一不存在的数据。例如:从缓存redis没有命中,需要从mysql数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透。
解决思路:
如果查询数据库也为空,直接设置一个默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库。设置一个过期时间或者当有值的时候将缓存中的值替换掉即可。
可以给key设置一些格式规则,然后查询之前先过滤掉不符合规则的 Key。
缓存并发
这里的并发指的是多个 redis 的 client 同时 set key 引起的并发问题。其实 redis 自身就是单线程操作,多个 client 并发操作,按照先到先执行的原则,先到的先执行,其余的阻塞。当然,另外的解决方案是把 redis.set 操作放在队列中使其串行化,必须的一个一个执行。
缓存预热
缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。
这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!
解决思路:
直接写个缓存刷新页面,上线时手工操作下;
数据量不大,可以在项目启动的时候自动进行加载;
目的就是在系统上线前,将数据加载到缓存中。
ES(ElasticSearch)
Elasticsearch 是一个分布式、RESTful 风格的搜索和数据分析引擎,能够解决不断涌现出的各种用例。 作为 Elastic Stack 的核心,它集中存储您的数据,帮助您发现意料之中以及意料之外的情况。
- 分布式实时文件存储,并将每一个字段都编入索引,使其可以被搜索。
- 实时分析的分布式搜索引擎。
- 可以扩展到上百台服务器,处理PB级别的结构化或非结构化数据。
基本概念
Elasticsearch 是面向文档型数据库,一条数据在这里就是一个文档,用JSON作为文档序列化的格式,比如下面这条用户数据:
1 |
|
索引
Elasticsearch最关键的就是提供强大的索引能力。
Elasticsearch索引的精髓:
一切设计都是为了提高搜索的性能
另一层意思:为了提高搜索的性能,难免会牺牲某些其他方面,比如插入/更新,否则其他数据库不用混了。前面看到往 Elasticsearch 里插入一条记录,其实就是直接PUT一个json的对象,这个对象有多个 fields,比如上面例子中的 name, sex, age, about, interests,那么在插入这些数据到 Elasticsearch 的同时,Elasticsearch 还默默的为这些字段建立索引–倒排索引,因为 Elasticsearch 最核心功能是搜索。
kafka
转载:https://www.jianshu.com/p/734cf729d77b
前言
消息队列的性能好坏,其文件存储机制设计是衡量一个消息队列服务技术水平和最关键指标之一。下面将从Kafka文件存储机制和物理结构角度,分析Kafka是如何实现高效文件存储,及实际应用效果。
1.1 Kafka的特性:
- 高吞吐量、低延迟:kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒,每个topic可以分多个partition, consumer group 对partition进行consume操作。
- 可扩展性:kafka集群支持热扩展
- 持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失
- 容错性:允许集群中节点失败(若副本数量为n,则允许n-1个节点失败)
- 高并发:支持数千个客户端同时读写
1.2 Kafka的使用场景:
- 日志收集:一个公司可以用Kafka可以收集各种服务的log,通过kafka以统一接口服务的方式开放给各种consumer,例如hadoop、Hbase、Solr等。
- 消息系统:解耦和生产者和消费者、缓存消息等。
- 用户活动跟踪:Kafka经常被用来记录web用户或者app用户的各种活动,如浏览网页、搜索、点击等活动,这些活动信息被各个服务器发布到kafka的topic中,然后订阅者通过订阅这些topic来做实时的监控分析,或者装载到hadoop、数据仓库中做离线分析和挖掘。
- 运营指标:Kafka也经常用来记录运营监控数据。包括收集各种分布式应用的数据,生产各种操作的集中反馈,比如报警和报告。
- 流式处理:比如spark streaming和storm
- 事件源
PHP-高并发和大流量的解决方案
原文链接:https://blog.csdn.net/m_nanle_xiaobudiu/java/article/details/79261765
高并发指的是在一个很短的单位时间内,有大量的用户对你的服务器发起请求。比如商城的“秒杀”或者淘宝的“双11”等。
高并发架构相关概念
QPS (每秒查询率) : 每秒钟请求或者查询的数量,在互联网领域,指每秒响应请求数(指HTTP请求)
PV(Page View):综合浏览量,即页面浏览量或者点击量,一个访客在24小时内访问的页面数量
–注:同一个人浏览你的网站的同一页面,只记做一次pv
吞吐量(fetches/sec) :单位时间内处理的请求数量 (通常由QPS和并发数决定)
响应时间:从请求发出到收到响应花费的时间
独立访客(UV):一定时间范围内,相同访客多次访问网站,只计算为1个独立访客
带宽:计算带宽需关注两个指标,峰值流量和页面的平均大小
日网站带宽: PV/统计时间(换算到秒) * 平均页面大小(kb)*
需要注意点
- QPS不等于并发连接数(QPS是每秒HTTP请求数量,并发连接数是系统同时处理的请求数量)
- 峰值每秒请求数(QPS)= (总PV数80%)/ (六小时秒数20%)【代表80%的访问量都集中在20%的时间内】
- 压力测试: 测试能承受的最大并发数 以及测试最大承受的QPS值
- 常用的性能测试工具:【ab,wrk,httpload,Web Bench,Siege,Apache JMeter】
对QPS各个层级的相应优化
QPS | 优化方案 |
---|---|
小于50 | 小型网站,不考虑优化 |
QPS达到100 | 数据查询瓶颈,考虑做数据库缓存层或者数据库的负载均衡 |
QPS达到800 | 带宽瓶颈,考虑使用CDN加速或者负载均衡 |
QPS达到1000 | HTML静态缓存 |
QPS达到2000 | 业务分离,分布式缓存 |
高并发解决方案
模 块 | 优 化 |
---|---|
流量 | 防止盗链,限制文件下载的大小 |
前端 | 减少HTTP请求(CSS,JS合并),异步请求,启用浏览器缓存,文件压缩,CDN加速,建立独立的图片服务器 |
服务器 | 页面静态化,并发处理,队列处理 |
数据库 | 数据库缓存,分区、分库、分表,读写分离,负载均衡 |
web服务器 | Nginx反向代理实现负载均衡,LVS实现负载均衡 |
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!