自2021/7/15开始
1.大并发服务器开发课程介绍
如果任务服务器的任务相同,就应该让应用服务器自动去取任务,这样比较公平。
任务服务器不应该只有一台,也要做负载均衡最终要做到:全面解耦合,哪个层面性能不足,就在那个层面增加服务器。
应用服务器的负载均衡
增加一个任务服务器来实现,任务服务器可以监视应用服务器的负载,CPU高、 I0高、并发高、内存换页高
查询到这些信息之后,选取负载最低的服务器分配任务。
应用服务器被动接收任务
应用服务器主动到任务服务器接收任务进行处理。
服务器性能四大杀手
1数据拷贝
2环境切换 (理性创建线程) 该不该用多线程,单线程好还是多线程好,单核服务器(采用状态机编程,效率最佳),多线程能够充分发挥
多核服务器的性能
3内存分配内存池
4锁竞争
大量的任务,提交到服务器
增加线程间的切换开销
进程切换,
队列+连接池
王要的业务逻辑挪到应用服务器处理,数据库只做辅助的业务处理
缓荐
缓存更新(缓存同步)缓存time out
如果缓存失效,重新去数据库查询,实时性 比较差
量数据库中数据更新,立即通知前端的缓存更新,实时性比较高。
缓存换页
内存不够,将不活跃的数据换出内存。FIFO
LRU (least recently used) (最近最少使用)
LFU(least frequently used) 最不频繁使用
nosql (反sq1) key / value
分布式缓存
redis
memcached
数据库读写分离
数据库的读操作>写操作
对数据库进行负载均衡replication机制
数据分区(分库、 分表)
I分库垂直分|
2 大型网站架构演变过程
2021/7/16
数据量访问过大,数据库就会出现锁竞争
锁竞争以及大表的连接,都会对数据库的性能产生很大的影响。应该是将相关性没那么大的数据从数据库中拿出放到数据存储中心存储,这里可以用NoSql数据库,如redis
基于分布式的文件系统:为什么要做这个?比如存一个图片,操作系统找一个小图片是非常耗时间的,因为操作系统的块比较小,而如果做成集成存储,一个块64M,里面专门放文件,通过key-value存储,使用hash算法,可以很轻松的找到文件。一次读一个块,供应多个图片请求。
谷歌的三大工具:GFS,BigTable,Map/Reduce 分布式文件系统,key-value数据库,分布式计算框架。
最开始,应用服务器和数据服务器和任务服务器都在一台主机上,后来数据服务器分离,应用服务器分为http服务器和具体逻辑处理服务器。
3 poll(一)
2021/7/17
服务器的11种状态
可以看看这个TCP的11种状态 其中C的状态为:closed syn_send estabilshed first_fin second_fin time_wait B的状态为closed syn_received established clopse_wait lask_ack closed
尽量让客户端关闭, 让time_wait发生在客户端。如果客户端已断开连接,再给他发信息操作系统就会给服务器发一个SIGPIPE信号,这个信号要屏蔽,否则会杀死进程。
这里创建socket文件:可以提前声明这个文件不阻塞,如果fork后被exec函数替换,这个文件自动关闭,如果不在这声明,也可以在fcntl种声明。另外还要声明一下端口复用。
poll是I/O多路复用,这里可以使用vector(向量)存储文件描述符数组,因为vector的删除比数组的删除方便。
4 poll(2)
2021/7/18
如果连接数过多,文件描述符已耗尽,那么服务器就会收到EMFILE的信号,这时的处理方法有如下几种:
处理方法
在这里面,最后一种是最好的选择。
上次写的poll函数实例是一条玩具代码,这是因为通信套接字可能会收到一次性读不完的代码,如果一次没读完,下次循环还会有POLLIN触发,而发送端也是如此,如果待发送的数据非常多,不能一次性发完,也应该有个缓冲区。
select内部实现用的是数组,写死在内核源码中,除非修改源码,poll是链表实现,epoll是红黑树,一个线程最多能打开的文件描述符和硬件有关,修改的话可以用ulimit -a查看然后修改,但不能超过允许的上限,上限可以在etc/security/limits.conf中修改。配置文件都在etc里面。
5 epoll (1)
2021/7/19
epoll有两种触发模式,LT(电平触发模式)与ET(边沿触发模式)
epoll的触发模式
10muduo_base库源码分析(一)
2021/7/20
同意程序轻松实现一个不可复制的类。有父类noncopyable的复制构造函数。从而禁止用户从外部訪问复制构造函数和复制赋值函数。
BOOST_STATIC_ASSERT是一个简单但常用的宏,顾名思义起到编译期断言的功效,可以通过它,在编译时对开发环境以及类型定义进行检查。此类型检测对程序运行时无任何效率和空间上的影响。
所谓值语义是指目标对象由源对象拷贝生成,且生成后与源对象完全无关,彼此独立存在,改变互不影响。就像 int 类型变量相互拷贝一样。对象语义也叫指针语义,引用语义等。通常是指一个目标对象由源对象拷贝生成,但生成后与源对象之间依然共享底层资源,对任何一个的改变都将随之改变另一个。
less_than_comparable是个模板类,提供类的比较功能:只要求提供<,就可自动实现>、<=、>=;
这一章主要讲时间戳函数。
11muduo_base库源码分析(二)
2021/7/21
为什么需要原子性操作?
如:x++;这一句其实要3句原子汇编指令。
从内存中读x的值到寄存器中,对寄存器加1,再把新
值写回x所处的内存地址。
gcc从4.1.2提供了_sync*系列的built-in函数,用于提供加减和逻辑运算的原子操作。
原子自增操作
type__sync_fetch_and_add (type *ptr, type value)
原子比较和交换(设置)操作
type__sync_val_compare_and_swap (type *ptr, type oldval type newval)
bool__sync_bool_compare_and_swap (type *ptr, type oldval type newwal)
原子赋值操作
type__sync_lock_test_and_set (type *ptr, type value)
用这些原子性操作,编译的时候需要加-march=cpu-type
无锁队列实现
volatile的作用:作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。简单地说就是防止编译器对代码进行优化。
当要求使用volatile声明的变量的值的时候,系统总是重新从它所在的内存读取数据,而不是使用保存在寄存器中的备份。即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。
12muduo_base库源码分析(三)
2021/7/22
Exception类实现
backtrace:栈回溯,保存各个栈帧的地址
backtrace_symbols,根据地址,转成相应的函数符号
abi::__cxal_demangle
17muduo_base库源码分析(八)
2021/7/23
在多线程环境中,有些事仅需要执行一次。通常当初始化应用程序时,可以比较容易地将其放在main函数中。但当你写一个库时,就不能在main里面初始了,你可以用静态初始化,但使用一次初始化(pthread_once)会比较容易些。
C库函数 int atexit(void (*func)(void)) 当程序正常终止时,调用指定的函数 func。您可以在任何地方注册你的终止函数,但它会在程序终止的时候被调用。
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
这句话其实就是定义了一个固定大小的char型数组,数组名为type_must_be_complete,数组大小是多少呢?是sizeof(T)?1:-1, ?:这个三元操作符大家都很熟悉了,若sizeof(T)非0,这个表达式的值为1,即typedef了一个大小为1的char型数组,否则定义一个大小为-1的数组。数组大小还能为负数?当然不能,于是就会报错,而且是编译期错误,于是就将一个动态运行时错误在编译时就发现了。
接下来解释sizeof什么时候返回0。C/C++语言本身似乎没有这种情况,但有些编译器会作一些扩展,比如GCC对于incomplete type使用sizeof时,会返回0。那什么又叫做incomplete type呢,就是那些声明了,但没有定义的类型,如前向声明。class A这样的。
从epoll构建muduo-2 最简单的epoll
2021/7/24
首先想到epoll_wait,要使用这个需要参数fd,epoll根节点以及事件,就创建fd,socket,将这两个绑定,监听,接收连接请求。就要先创建epoll树,得到树的根节点。wait有了返回值之后,就得用这个返回值做循环。
从epoll构建muduo-3 加入第一个类,顺便介绍reactor
2021/7/25
主要类之间的关系图,很难懂。
网友评论