NoSQL 概述
NoSQL
含义
Not Only SQL
和 SQL 的区别
SQL
- 适合存储结构化的数据
- 数据需要做结构化查询,eg:join
- 数据的规模,增长的速度通常是可以预期的
- 需要保证数据的事务性,一致性要求
- 缺点
- 读写性能
- 表结构更新:如果表里有较多数据时候,有比较大的结构变更会耗时较长
- 高并发:每秒上万次读写请求,对于传统关系型数据库来说,硬盘IO是一个很大的瓶颈
- 海量数据:对于关系型数据库来说,在一张包含海量数据的表中查询,效率是比较低的
NoSQL
- 适合存储非结构化数据
- 这些数据通常用于模糊处理,eg :全文搜索,机器学习
- 数据是海量的,而且增长速度难以预期
- 根据数据的特点,NoSQL 数据库通常具有无限(至少接近无限)的伸缩性
- 按key获取数据的效率很高,但是对join或者其他结构化查询的支持就比较差
常见类型
键值类(key-value)
- 产品:memcached,Redis
- 应用场景:内容缓存,主要用于处理大数据的高访问负载
- 优点:查找速度快
- 缺点:数据无结构化,通常只被当做字符串或者二进制数据
列式数据
- 按列存储数据
- 大特点是方便存储结构化和半结构化数据,方便做数据压缩,针对某一列或者某几列查询有较大的IO优势
- 产品:HBase,BigTable,Cassandra等
- 优点
- 查找速度快,可拓展性强,容易分布式拓展
- 缺点
- 功能相对局限
文档类
- 将半结构化数据存储为文档,通常采用JSON或者XML 格式
- 应用场景:存储类似JSON格式的内容,可以对某些字段建立索引功能,是想关系型的数据库
- 产品:MongoDB,couchBase
- 优点:数据结构要求不严格,表结构可变,不需要像关系型数据库一样需要预先定义表结构
- 缺点:查询性能不太高
图形类
- 可以存储顶点以及成为边缘的直接链路
- 数据模型:图结构
- 典型应用场景:社交网络,推荐系统等。专注于构建关系图谱,善于处理大量复杂,互连接,低结构化的数据,数据变化迅速,且查询频繁
- 优点:利用图结构相关算法,比如短路径寻址,N度关系查找等
- 缺点:很多时候需要对整个图做计算才能得出需要的信息,而且这种结构不太好做分布式的集群方案
数据分片
单节点
按id范围分片
- 缺点:可能存在早的 都是冷数据,新的都是热数据
按hash取模分片
- Node = Hash(Key) % 结点总个数
- 缺点:不利于拓展,加入或者减少结点之后, 要全部重新分片
一致性Hash取模
- 算法
- 先构造一个长度为232的整数环(这个环被称为一致性Hash环),
- 根据节点名称的Hash值(其分布为[0, 232-1])将服务器节点放置在这个Hash环上,
- 然后根据数据的Key值计算得到其Hash值(其分布也为[0, 232-1]),接着在Hash环上顺时针查找距离这个Key值的Hash值近的服务器节点,完成Key到服务器的映射查找。
- 优点
- 如果增加或者减少结点,不必像hash取模那样 ,需要重新分片,只进行部分分片就可以。
- 缺点:一个节点失效后,紧邻着的下一个节点压力会增大,会造成负载不均衡。如果下一个节点不能承受压力,会造成雪崩
基于虚拟节点的一致性Hash取模
- 原理
- 将一个物理节点拆分为多个虚拟节点,并且同一个物理节点的虚拟节点尽量均匀分布在Hash环上。
- 优点
- 一个真实结点不再固定在Hash换上的某个点,而是大量地分布在整个Hash环上,这样即使上线、下线服务器,也不会造成整体的负载不均衡。
Hash 槽
- 其实哈希槽的本质和一致性哈希算法非常相似,
- 不同点就是对于哈希空间的定义。
- 一致性哈希的空间是一个圆环,节点分布是基于圆环的,无法很好的控制数据分布。
- 而Redis Cluster的槽位空间是自定义分配的,类似于Windows盘分区的概念。这种分区是可以自定义大小,自定义位置的。
- 每个Key通过计算后都会落在具体一个槽位上,而这个槽位是属于哪个存储节点的,则由用户自己定义分配。例如机器硬盘小的,可以分配少一点槽位,硬盘大的可以分配多一点。如果节点硬盘都差不多则可以平均分配。
数据分片的实现方式
- 客户端分片(Client side partitioning)
- 客户端直接选择正确的节点来写入和读取指定键
- 代理协助分片(Proxy assisted partitioning)
- 客户端发送请求到一个可以理解 服务端(eg:redis)协议的代理上,而不是直接发送请求到 服务端实例上。代理会根据配置好的分片模式,来保证转发我们的请求到正确的 服务端实例,并返回响应给客户端。
- 查询路由(Query routing)
- 你可以发送你的查询到一个随机实例,这个实例会保证转发你的查询到正确的节点。
- 或者 直接返回给客户端要查询的正确的结点数据,客户端重新去正确的结点查询
相关文章