1.服务器的设计目标
- 高性能(High Performance),主备机使用TCP通信,不使用共享内存
- 高可用(High Availability),服务器24h都可用,故障可转移备机
- 伸缩性(Scalability),对于大并发请求,能快速响应
2.分布式
- 负载均载
- 分布式存储
- 分布式计算
2.C/S架构
- 任何网络系统都可以抽象为C/S结构
(1)其中S1和S2也相当于一个C/S 结构
(2)B/S架构也C/S 结构中的一种。
Ie浏览器httpc客户端,通过http协议访问http服务器,httpd服务器返回一个web界面给http客户端
3.一个典型的服务器结构
- 网络I/O + 服务器高性能编程技术 + 数据库
- 超出数据库连接数
数据库并发连接数10个,应用服务器这边有1000个并发请求,将会有990个请求失败 - 超出时限
数据库并发连接数10个,数据库1秒钟之内最能处理1000个请求,应用服务器这边有10000个并发请求,会出现0-10秒的等待。
-
APP:应用服务器
-
DAL:数据访问层,这是一个队列,DAL既可以与app部署在同一台机器上,也可以单独部署(伸缩性)
-
如何减轻数据库压力?提高数据库的并发能力?
(1)队列+连接池
DAL队列服务+连接池,DAL与DB的连接放到连接池里面,下次访问就直接从连接池中取出一个连接就可以了,不用创建新的连接
(2)主要的业务处理应该放在应用服务器(即操作系统上面),而数据库只做辅助的业务处理,来降低数据库压力
(3)使用缓存可以减少对数据库的访问
方法1: 缓存是有time out的时效的
使用缓存的问题:缓存更新问题(即缓存同步),如果缓存失效,就重新去数据库查询,再更新缓存,这种方法不是实时的,实时性较差;
方法2: 将热点数据放在缓存中
来自app的业务请求如果要更新数据库的内容,会直接update数据库中的内容,然后,返回来时,数据库会更新缓存中的内容;
一旦数据库中的数据更新,立即通知前端的缓存更新,实时性比较高
缓存换页:若内存不够,就将不活跃的数据换出内存:FIFO,LRU(least recently used最近最少使用),LFU(Least frequently used)最不频繁使用
(4)开源实现eg:nosql非关系数据库,即反sql,对数据一致性要求不是很高的,基于key/value的数据。eg:redis,memcached等分布式缓存。
所以,cache既可以与app部署在一起,也可以与DB部署在一起。但是前者会使cache的数据成为局部的,如果有多个app,则不好,所以cache若是分布式缓存,则可避免,因为大家都可以访问 -
数据库读写分离
(1)数据库的写操作,会把数据库锁住,那么其它的业务请求过来就会阻塞住,等待写操作完成
(2)因为大部分的应用来说,数据库的读操作次数> 写操作,可以使用replication机制对数据库进行负载均衡。
(3)master用来写操作,slave用来读操作。master发生数据改变,需要将数据同步到slave数据库(方法:通过日志文件进行同步),这也叫做replication机制 -
一个app应用服务器可以处理多个应用,也可以是不同APP处理单个业务
最好先经过任务服务器,实现负载均衡;
任务服务器可以监控app应用服务器的状态(通过暴露接口的方式给任务服务器),app服务器相当于http服务端,任务服务器相当于http客户端;
(1)应用服务器被动接受任务:任务服务器来可以监视应用服务器的负载,CPU,IO,并发,内存换页,查询到这些信息之后,选取负载最低的服务器来分配任务;
(2)应用服务器主动到任务服务器取任务:这种方式最科学,哪台应用服务器空闲了,就去任务服务器取任务,前提:若所有应用服务器处理的业务类型都是一样的
任务服务器之间通过心跳机制,若一台故障了,另外一台能够使用;
-
数据库的数据分区(分库,分表)
(1)分库:垂直分区。
若数据库有:用户表,业务表,基础表,可将其分为三个库。相当于有3个主从的库。
(2)分表:水平分区。
若数据库有:用户表,业务表,基础表,若用户表是10条记录,就将其切分到10个数据库,每个数据库只有1条记录。用的多。
-
哪一个层面出现瓶颈,就在哪个层面增加服务器。
任务服务器出现瓶颈,就增加任务服务器的数量,以此类推
4.服务器性能的4大杀手
- 数据拷贝:利用缓存来解决
eg:从内核拷贝数据到用户态等 - 理性创建线程:单线程好,还是多线程好?
(1)单核服务器,采用状态机编程,效果最好,因为大量的任务,提交到服务器,会增加线程间的切换开销,此外,进程切换开销也很大,因为一个CPU的时间将其分给多个进程,每个进程有自己的执行状态;
(2)多核服务器,多线程能够充分发挥多核服务器的性能,也要尽可能减少线程之间的上下文切换。 - 内存分配
增加内存池,减少对OS申请内存 - 锁竞争
用逻辑避免锁的使用,减少锁的使用