一、前置知识
1.读写速度
1.1.磁盘
- 寻址:毫秒ms级别的。
- 带宽:单位时间内能传输的字节流能有多少,几个G或几M。
1.2.内存
- 寻址:纳秒ns级别的。
秒=1000毫秒=10001000微妙=10001000*1000纳秒。在寻址上,磁盘比内存慢了10万倍。
- 带宽:很大
2.I/O Buffer
- 磁盘有磁道、扇区,一扇区为512 Byte,如果每次从磁盘读取512 Byte会带来一个成本问题,即索引体积太大(叶太多),所以操作系统无论读多少数据,最少从磁盘读取4K大小的数据。
一般操作系统4K,不会造成浪费,也支持存储一些小文件,假如说服务器想做视频录像之类的,4K大小的话,就有点得不偿失,不如换的大一点,一次性读的东西多一些,减少磁盘寻址时间。4K大小其实取决于上层应用对IO的使用量,是IO密集型还是一些小文件。
- 随着文件变大,速度会越慢,磁盘IO会成为瓶颈。
二、数据库
-
数据库的出现是为了改善磁盘IO的瓶颈。但整体而言,磁盘IO和数据库的IO总量是相等的,因此就有了索引的概念,如果没有索引,仅仅只是建了数据库和表,不会有太大帮助,依旧很慢。
-
开始数据是存储在文件中的,随着文件变大,数据增多,查询会变慢。为什么?磁盘I/O成为瓶颈,数据库出现,定义每个data page 大小为4K,把数据存储到一个个的data page中,与操作系统读取数据大小一致,即每次都是一次I/O,但是此时还是全量IO,并没有加快查询速度,必须建立索引,索引也是4K大小,指向每个data page。数据和索引都是存储在磁盘中的,在内存中还有一个B+树(树干)。
流程为:用户请求,命中索引,索引加载到内存,然后解析完,得知下次该读取哪一页上的数据,再将其加载到内存读取。充分利用内存读取快,磁盘存储容量大的特点。
- 数据库中最小的单位为page页,以4k为单位。
- 关系型数据库建表,必须先给出schema,数据类型(字节宽度),存数据时倾向于行级存储。先给出字节宽度的好处时,保留了位置,在插入或更新数据时直接进行覆写而不用进行数据移动。
- 索引也是数据,和表数据一样都存储在硬盘中。在内存中创建一棵B+树用于将索引的区间和偏移存储起来,索引和数据存在磁盘,因为内存有限,存不下这么多的数据,利用索引提高遍历查找的速度,减少磁盘IO和寻址的过程,但数据还是从磁盘获取。
这里引出一个问题:数据库表数据量大的时候,性能下降?(从寻址和带宽两个方面回答)
- 前提:如果表有索引
增删改:会变慢,因为要维护索引,即索引中的数据需要移动。
查询速度:如果是1个或少量请求的话,查询速度依然很快。
如果是大量并发请求,而刚好查询的数据又落在不同的page页上,磁盘的带宽会影响查询速度。原因是需要依次把page页上的数据加载到内存,当数据量大的时候,就会很慢。
三、折中方案
四、Memcached和Redis的区别
- Memcached也是k,v存储形式,但是value没有类型的概念,而Redis的value有类型的概念。
- 通常存储数据的方式有三种:
k = 1 k = a
k = [1,2,3] k = [a,b,c]
k = {k=a} k = {[1,2],[3,4],[5,6]}
- 但从存储结构来看,k,v也可以存储复杂类型数据,即满足所有需求,为什么value要分类型呢?可以拿一个client从缓存中取出某一个元素来分析:
Memcached
第一,返回value所有的数据到client,server端网卡IO会拖慢
第二,客户端需要编写复杂的代码解码返回的数据
Redis
value的类型并不是最重要的,重要的是Redis的server中有对应每种类型的方法,客户端只需调用对应方法即可,不需要编写复杂代码。(计算向数据移动:memcached会返回大量结果数据,然后在client解码;而Redis server直接根据类型的方法得到结果数据,将少量的数据返回给client!)