内存池系列|MC内存分配
slab allcator的机制
综合上面的介绍,memcached的内存分配策略就是:按slab需求分配page,各slab按需使用chunk存储。
这里有几个特点要注意,
Memcached分配出去的page不会被回收或者重新分配
Memcached申请的内存不会被释放
slab空闲的chunk不会借给任何其他slab使用
内存池系列|nginx内存分配
有几个:
- nginx_pool_s 虽然包含了 ngx_pool_data,但是nginx_pool_s本身的内存管理还是通过ngx_pool_data来进行分配的
- 可以理解为:nginx_pool_s是一种特殊类型的ngx_pool_data。
- nginx_pool_s 维护了current指针,来指向下一个用来分配内存的小内存块链表节点
- nginx_pool_s 维护了large指针,来指向下一个用来分配内存的d大内存块链表节点
- ngx_pool_data 维护了next指针 来指向下一个nginx_pool_s
内存池系列|STL内存分配
- 基于hash的freelist
- 由于STL知道分配出去的内存对象大小,所以他技巧性地用了union来减少内碎片。
设计模式-reactor模式
Reactor 模式首先是事件驱动的,有一个或多个并发输入源,有一个Service Handler,有多个Request Handlers;这个Service Handler会同步的将输入的请求(Event)多路复用的分发给相应的Request Handler。如果用图表示的如下:
其实在设计模式层面,IO多路复用也是采用 Reactor 模式的。
IO 多路复用模型可以看成是 Reactor 模式在 IO 模型上的应用。
分布式系统-低延迟,高性能
在我看来,高性能指的是,我们的系统能够在尽可能短的时间内完成用户的请求,也就是说latency尽可能的低。
如果说系统能够支撑更大的吞吐量,能够承载更多的同时在线。我们除了降低latency,还可以考虑加机器(如果还没有reach到某个系统平瓶颈的前提下)
提高吞吐量
增加并发进程数
注意:无限增加,不会无限提升性能(对系统的扩展性有要求)
减少响应时间
IO密集型:优化数据库索引、加缓存
CPU密集型:优化算法时间复杂度、减少不必要运算等
并发读的核心优化理念是尽量减少用户到服务端来“读”数据,或者让他们读更少的数据;
并发写的处理原则也一样,它要求我们在数据库层面独立出来一个库,做特殊的处理。
从一个架构师的角度来看,要想打造并维护一个超大流量并发读写、高性能、高可用的系统,在整个用户请求路径上从浏览器到服务端我们要遵循几个原则,就是要保证
- 用户请求的数据尽量少
- 完成这个请求的路径尽量短、依赖尽量少 =》 上游到下游的请求数尽量少
也就两个大的方向:提升单次效率、减少不必要的请求
- 动静分离方案(移除无关依赖、减少请求)
- 热点的发现与隔离(缩短热点的服务路径)
- 请求的削峰与分层过滤(异步化,减少无必要的依赖)
- 服务端的极致优化(缩短热点的服务路径)
分布式系统-可扩展
一些概念
有合理的办法应对系统的增长(数据量、流量、复杂性)
一个良好适配应用的可扩展架构,是围绕着假设(assumption)建立的:哪些操作是常见的?哪些操作是罕见的?这就是所谓负载参数。如果假设最终是错误的,那么为扩展所做的工程投入就白费了,最糟糕的是适得其反。
数据库、缓存、依赖的第三方、复杂均衡、交换机带宽都是系统扩展时需要考虑的点
分层
首先要分层,分层是实现扩展的必要条件;分了层才能让系统有更好的可扩展能力;
我们将系统分为如下几层:
接入层
主要负责负载均衡,要求负载均衡策略的时间复杂度要尽量简单,追求$O(lgn)$的时间复杂度,最坏不能超过$O(n)$。对于更坏时间复杂度的均衡策略,性能上会扛不住。
应用层
业务层:按照业务拆分、按照重要性拆分(轻重分离,核心、非核心)、按照请求来源(客户端、web、内网等)—这个跑偏了,这些点主要服务于可用性。
这里侧重点在于无状态,我们一定要确保我们的服务无状态。
存储层
存储层做扩展会更麻烦一些。
一般情况下,要求我们根据业务量提前估计好存储容量。根据计算出来的总的存储量,提前做足够的数据分片。
换言之,对于存储层,我们的一种思路是:早做扩展,以确保将来不做扩展;
另外一种思路是,添加必要的路由层(数据访问路由层)或者路由算法(数据表倍增法),来确保将来的扩展对上层不可见。
manager层
- 抽象service层可能提供的一些原子能力
- 封装对第三方接口的调用
高性能服务器设计-总览
池化技术
核心思想:用空间换时间,期望使用预先创建好的对象来减少频繁创建对象的性能开销,同时还统一管理了对象,降低了对象的使用成本。
例子:
(1)数据库连接池-最小数量、最大数量、如果超过最大则等待
(2)线程池-最小数量、最大数量、有界队列(监控队列中元素的个数)
线程池大小:区分IO密集、CPU密集
(3)内存池
超时事件管理
IO模型
线程模型,一般会综合考虑IO模型、超时事件如何管理、线程池、消息队列等
存储系列-概览
存储模型有哪些?
关系模型
文档模型:数据通常是自我包含的,而且文档之间的关系非常稀少
图数据模型:任意事物都可能与任何事物相关联