并发处理
进程(Process)
是计算机中程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单元,是操作系统结构的基础。进程是一个执行中的程序
进程的三态模型:运行、就绪、阻塞
进程的五态模型:新建态、活跃就绪/静止就绪、运行、活跃阻塞/静止阻塞、终止态
新建态:对应于进程刚刚被创建时没有被提交的状态,并等待系统完成创建进程的所有必要信息
终止态:进程已结束运行,回收除进程控制块之外的其他资源,并让其他进程从进程控制块中收集有关信息。
活跃就绪:是指进程在主存并且可被调度的状态。
静止就绪(挂起就绪):是指进程被对换到辅存时的就绪状态,是不能被直接调度的状态,只有当主存中没有活跃就绪态进程,或者是挂起就绪态进程具有更高的优先级,系统将把挂起就绪态进程调回主存并转换为活跃就绪。
活跃阻塞:是指进程已在主存,一旦等待的事件产生便进入活跃就绪状态。
静止阻塞:进程对换到辅存时的阻塞状态,一旦等待的事件产生便进入静止就绪状态。
线程
线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源但它可与同属一个进程的其它线程共享进程所拥有的全部资源。
一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。
线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。
在单个程序中同时运行多个线程完成不同的工作,称为多线程。
协程
协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
区别
线程与进程
线程是进程内的一个执行单元,进程内至少有一个线程,它们共享进程的地址空间,而进程有自己独立的地址空间
进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
线程是处理器调度的基本单位但进程不是
二者均可并发执行
每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
协程和线程
一个线程可以多个协程,一个进程也可以单独拥有多个协程
线程进程都是同步机制,而协程则是异步
协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态
例子
单进程单线程:一个人在一个桌子上吃菜
单进程多线程:多个人在同一个桌子上一起吃菜
多进程单线程:多个人每个人在自己的桌子上吃菜
同步阻塞
多进程模式
创建一个 socket
进入 while循环,阻塞在进程accept操作上,等待客户端连接进入主进程在多进程模型下通过fork刨建子进程
收到数据后服务器程序进行处理然后使用send向客户端发送响应
当客户端连接关闭时,子进程/线程退出并销毁所有资源。主进程/线程会回收掉此子进程/线程。
多线程模式
多线程模型下可以创建子线程
子进程/线程创建成功后进入while循环,阻塞在recv调用上,等待客户端向服务器发送数据
收到数据后服务器程序进行处理然后使用send向客户端发送响应
当客户端连接关闭时,子进程/线程退出并销毁所有资源。主进程/线程会回收掉此子进程/线程。
缺点
这种模型严重依赖进程的数量解决并发问题
启动大量进程会带来额外的进程调度消耗
异步非阻塞
现在各种高并发异步IO的服务器程序都是基于epoll实现的
IO复用异步非阻塞程序使用经典的Reactor模型,Reactor顾名思义就是反应堆的意思,它本身不处理任何数据收发。只是可以监视一个 socket句柄的事件变化
reactor模型
Add:添加一个 SOCKET到 Reactor
Set:修改 SOCKET对应的事件,如可读可写
Del:从 Reactor中移除
Callback:事件发生后回调指定的函数
常见reactor模型
Nginx:多线程 Reactor
Swoole:多线程 Reactor+多进程Worker
数据库缓存
mysql查询缓存
查询缓存可以看做是SQL文本和查询结果的映射,第二次查询的SQL和第一次查询的SQL全相同,则会使用缓存
表的结构或数据发生改变时,查询缓存中的数据不再有效
配置:
query_cache_type
查询缓存类型,有0、1、2三个取值。0则不使用查询缓存。1表示始终使用查询缓存。2表示按需使用查询缓存。
query_cache_size
默认情况下 query_cache_size
为0,表示为查询缓存预留的内存为0,则无法使用查询缓存
SET GLOBAL query_cache_size= 134217728
使用
querycache_type
为1时,亦可关闭查询缓存
SELECT SQL_NO_CACHE FROM my_table WHERE condition;
query_cache_type
为2时,可按需使用查询缓存
SELECT SQL_CACHE FROM my_table WHERE condition;
其他
查看命中次数
SHOW STATUS LIKE'Qcache_hits';
清理缓存
FLUSH QUERY CACHE∥清理查询缓存内存碎片
RESET QUERY CACHE∥从查询缓存中移出所有查询
FLUSH TABLES;//关闭所有打开的表,同时该操作将会清空查询
缓存中的内容
redis
/ memcache
缓存
Redis,依赖客户端来实现分布式读写
Memcache本身没有数据冗余机制
Redis支持(快照、AOF),依赖快照进行持久化,aof增强了可靠性的同时,对性能有所影响
Memcache不支持持久化,通常做缓存,提升性能;
Memcache在并发场景下,用cas保证一致性, redis事务支持比较弱,只能保证事务中的每个操作连续执行
Redis支持多种类的数据类型
Redis用于数据量较小的高性能操作和运算上
Memcache用于在动态系统中减少数据库负载,提升性能;适合做缓存,提高性能
mysql 优化
数据表数据类型优化
tinyint、 smallint、 bigint 考虑空间的问题,考虑范围的问题
char、varchar
enum 特定、固定的分类可以使用enum存储,效率更快
ip地址 ip2long() 转成长整型存储
索引优化
索引创建原则
索引不是越多越好,在合适的字段上创建合适的索引
复合索引的前缀原则
索引注意事项
复合索引的前缀原则
like查询%的问题
全表扫描优化
or条件索引使用情况
字符串类型索引失效的问题
SQL语句的优化
优化查询过程中的数据访问
使用 Limit
返回列不用*
优化长难句的查询语句
变复杂为简单
切分查询
分解关联查询
优化特定类型的查询语句
优化 count()
优化关联查询
优化子查询
优化 Group by和 distinct
优化 limit和 union
存储引擎的优化
尽量使用 Inno DB存储引擎
数据表结构设计的优化
分区操作
通过特定的策略对数据表进行物理拆分
对用户透明
partition by
分库分表
水平拆分
垂直拆分
数据库服务器架构的优化
主从复制
读写分离
双主热备
负载均衡
负载均衡
通过LVS的三种基本模式实现负载均衡
MyCat数据库中间件实现负载均衡
web服务器的负载均衡、请求分发
七层负载均衡实现
基于URL等应用层信息的负载均衡
Nginx的 proxy是它一个很强大的功能,实现了7层负载均衡
nginx负载均衡
优点
功能强大,性能卓越,运行稳定
配置简单灵活
能够自动剔除工作不正常的后端服务器
上传文件使用异步模式
支持多种分配策略,可以分配权重,分配方式灵活
Nginx负载均衡策略
内置策略: IP Hash、加权轮询
扩展策略:fair策略、通用hash、一致性hash
加权轮询策略
首先将请求都分给高权重的机器,直到该机器的权值降到了比其他机器低,才开始将请求分给下一个高权重的机器
当所有后端机器都down掉时,Ngnx会立即将所有机器的标志位清成初始状态,以避免造成所有的机器都处在 timeout的状态
IP Hash策略
Nginx内置的另一个负载均衡的策略,流程和轮询很类似,只是其中的算法和具体的策略有些变化
IP Hash算法是一种变相的轮询算法
fair策略
根据后端服务器的响应时间判断负载情况,从中选出负载最轻的机器进行分流
通用Hash、一致性Hash策略
通用hash比较简单,可以以 Nginx内置的变量为key进行hash,
一致性hash采用 Nginx了内置的一致性hash环,支持 memcache
配置
http {
upstream cluster {
server srvl;
server srv2;
server srv3;
}
server {
listen 80;
location /
proxy_pass http: //cluster;
}
}
四层负载均衡实现
通过报文中的目标地址和端口,再加上负载均衡设备设置的服务器选择方式,决定最终选择的内部服务器
LvS实现服务器集群负载均衡有三种方式,NAT,DR和TUN