常识:
- 磁盘:
- 寻址:ms;
- 带宽:G/M;
- 内存(寻址比硬盘快10万倍)
- 寻址:ns;
- 带宽:很大(走cpu总线);
- I/O buffer:成本问题
磁盘有磁道和扇区;
一扇区512Byte;
操作系统无论从磁盘读多少都是最少4K;
数据存储发展进程
随着文件变大查询速度变大,硬盘io成为瓶颈;
数据库:
data page:
定义小了浪费定义大了无所谓,4K刚好和磁盘能对上,一堆4K连在一起,每个4K都要读取走的就是全量io,
- 怎么能变快?
索引也使用的4K,存的指向关系,随着数据变大索引也会很多, - 关系型数据库存储方式
建表必须给出schema多少列类型:字节宽度,以行单位存储, - 内存中的B+树
所有的叶子是4K,树干在内存(区间和偏移),用户想查sql条件where命中索引了,树干会找到某个叶子会把这个区间从硬盘读取到内存,遍历完后知道下次把哪个data page读进来就找到记录的数据; - 最终目的
减少磁盘io的流量,减少寻址的过程,
随着数据量变大,几百万行 1T2T,性能变低
如果表有索引,维护索引会增删改变慢,查询速度不会变慢
- 数据有100T,树干也都能存下,哪儿都没有溢出,来了少量的sql where命中索引依然很快,因为依然走的是一个datapage;
- 并发来了或复杂sql来了,要获取多个datapage到内存散在不同4K上,受硬盘带宽速度影响,有一部分人等待别人的4K走完才会走自己的4K;
极端
- 数据在内存和磁盘体积不一样,磁盘没有指针的概念,内存可以同一份数据指向不同的地方;
- 关系型数据库的2T数据放到非关系型数据库有可能只占用1.5T空间,HANA非关系型数据库很贵公司买不起;
- 硬盘慢内存贵所以折中了出现了硬盘到内存中间的概念:缓存,一部分数据放到内存里;
- memcached
- redis每秒15万笔操作
问题
外部网络问题出现了:双写一致问题
数据库引擎介绍
从下面网站可以查到所有的数据库引擎的详细信息,可以做技术选型
- https://db-engines.com/en/
- DB-Engines Ranking(排名)
- system(百科)
redis简单介绍
官网
https://redis.io/
https://redis.com/
http://redis.cn/
特点
- 可以用作数据库、缓存和消息中间件
- 丰富的数据类型和api
直接用字符串存json也可以,客户端想通过缓存系统取回value中的某一个元素,- memcache需要返回所有数据到client那么网卡io会成为瓶颈client要有自己解析json;
- redis重要的不是类型,redis对每种类型都提供了api,客户端不需要取很多数据,网卡io也ok,客户端代码也轻盈;
计算向数据移动
:不是拿数据回来计算的,而是调了方法在服务端计算;
redis实操
环境依赖
yum install wget
yum groupinstall base
cd /etc/sysconfig/network-scripts/
- centos6
yum install gcc
- centos7
yum install gcc-c++ 安装的gcc是4.5.8版本的,版本过低,执行以下命令升级gcc即可
yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
scl enable devtoolset-9 bash
echo “source /opt/rh/devtoolset-9/enable” >> /etc/profile
gcc -v
下载
wget http://download.redis.io/releases/redis-6.0.6.tar.gz
tar xf redis-6.0.6.tar.gz
安装
源码安装都是一个套路,上来看redme.md
make命令编译
可以强调编译成32或64位或test
编译清除
make命令编译过程
这里已经生成好了Makefile,make的是Makefile,但是Makefile指向的是真正干活的src/Makefile这里边是具体的编译安装的执行命令;
编译完
- 找到可执行程序运行
服务级安装到系统里
执行make install
,设置安装位置默认位置/usr/local/bin
然后执行,有前后端脚本和一系列输出,完成服务级安装
具体实现
-
redis安装到目录
make install PREFIX=/opt/application/redis6
-
修改环境变量,添加到末行,这样redis命令在全局可以使用
vim /etc/profile export REDIS_HOME=/opt/application/redis6 export PATH=$PATH:$REDIS_HOME/bin source /etc/profile echo $PATH
-
安装redis服务实例
-
输入启动命令./install_server.sh报错
This systems seems to use systemd. Please take a look at the provided example service unit files in this directory, and adapt and install them. Sorry!
注释下面的代码即可
#bail if this system is managed by systemd #_pid_1_exe="$(readlink -f /proc/1/exe)" #if [ "${_pid_1_exe##*/}" = systemd ] #then # echo "This systems seems to use systemd." # echo "Please take a look at the provided example service unit files in this directory, and adapt and install them. Sorry!" # exit 1 #fi
-
-
安装完成
redis安装实操总结
IO模型epoll介绍
BIO
直接调的内核read(fd)接口把文件描述符传进去,
文件描述符过来一个执行完在执行下一个;
NIO
1个线程的成本,线程栈是独立的默认1MB;
死循环疯狂调用内核传文件描述符,谁有就返回谁,
- 解决了bio
- 弊端:cpu浪费、内存成本
select
把所有fd扔给内核select接口,select把有响应的fd给线程,再由线程调read
- 解决了:疯狂遍历文件描述符
- 弊端:每次都要传1000到内核,用户态内核态传递数据成本高;
epoll
用户态和内核态有共享空间,fd都放在共享空间mmap接口映射,fd红黑树存储有响应的fd放到链表,线程直接读链表;
- 有3个调用 create 会返回epoll.fd,有连接了就写给epoll.fd的共享空间,只需要维护红黑树,
- 用户空间调epoll ctl add真实socket.fd和wait()等待
- 链表有了wait()就返回
- 然后进程自己调read()
0拷贝sendfile
0拷贝不是fd之间的,而是用户态和内核态两个用户空间;
- 这个之前有read和write,网卡有socket.fd文件有file.fd,先由内核调read读到用户态处理完再由用户态写出,就存在内核态拷贝到用户态;
- 有了sendfile
直接调一个sendfile(),文件读到内核,内核读file直接放入缓冲区,然后直接发出去,就不考来考去了;
- mmap+sendfile=kafka
kafka有网卡来的数据,网卡来的数据走kafka,kafka是jvm用户态进程
网卡-内核-它(mmap可以对files和进行挂载到文件)又因为mmap内核空间是共享的,直接触发内核减少系统调用,减少拷贝;
用户通过sendfile读文件;
redis原理
客户端socket.fd排着队进来, 到了Linux内核,因为redis是进程调了内核的epoll,所以mmap读取链表有一个读一个,而且redis是内存的没有io网卡是有io;
分布式多线程:每个连接内的命令顺序可以保证;
redis使用
- redis-cli -h 连接帮助文档
- 一共16个库默认0库
- 帮助文档