聊聊数据库~开篇

1.前言

总是聊并发的话题,聊到大家都免疫了,所以这次串讲下个话题——数据库(欢迎纠正补充)

看完问自己一个问题来自我检测:NoSQL我到底该怎么选?

1.1.分类

主要有这么三大类:[再老的数据库就不说了]

1.传统数据库(SQL):

  • 关系数据库:SQLite、MySQL、SQLServer...

2.高并发产物(NoSQL):

  1. 键值数据库:Redis、MemCached...
  2. 文档数据库:MongoDB、CouchBase、CouchDB、RavenDB...
  3. 列式数据库:CassandraHBase、BigTable...
  4. 图形数据库:Neo4J、Infinite Graph、InfoGrid...

3.新时代产物(TSDB):

  • 时序数据库:InfluxDBLogDevice...

来看个权威的图:(红色的是推荐NoSQL,灰色是传统SQL)

1.2.概念

先说下NoSQL不是不要使用传统SQL了,而是不仅仅是传统的SQL(not only sql)

1.关系型数据库优劣

先看看传统数据库的好处:

  1. 通过事务保持数据一致
  2. 可以Join等复杂查询
  3. 社区完善(遇到问题简单搜下就ok了)

当然了也有不足的地方:

  1. 数据量大了的时候修改表结构。eg:加个字段,如果再把这个字段设置成索引那是卡到爆,完全不敢在工作时间搞啊
  2. 列不固定就更蛋疼了,一般设计数据库不可能那么完善,都是后期越来越完善,就算自己预留了保留字段也不人性化啊
  3. 大数据写入处理比较麻烦,eg:
    1. 数据量不大还好,批量写入即可。
    2. 可是本身数据量就挺大的,进行了主从复制,读数据在Salver进行到没啥事,但是大量写数据库怼到Master上去就吃不消了,必须得加主数据库了。
    3. 加完又出问题了:虽然把主数据库一分为二,但是容易发生数据不一致(同样数据在两个主数据库更新成不一样的值),这时候得结合分库分表,把表分散在不同的主数据库中。
    4. 完了吗?NoNoNo,想一想表之间的Join咋办?岂不是要跨数据库和跨服务器join了?简直就是拆东墙补西墙的节奏啊,所以各种中间件就孕育而生了【SQLServer这方面扩展的挺不错的,列存储也自带,也跨平台了(建议在Docker中运行)(点我查看几年前写的一篇文章)】
    5. 欢迎补充~(说句良心话,中小型公司SQLServer绝对是最佳选择,能省去很多时间)

2.NoSQL

现在说说NoSQL了:(其实你可以理解为:NoSQL就是对原来SQL的扩展补充

  1. 分表分库的时候一般把关联的表放在同一台服务器上,这样便于join操作。而NoSQL不支持join,反而不用这么局限了,数据更容易分散存储
  2. 大量数据处理这块,读方面传统SQL并没有太多劣势,NoSQL主要是进行缓存处理,批量写数据方面测试往往远高于传统SQL,而且NoSQL在扩展方面方便太多了
  3. 多场景类型的NoSQL(键值,文档、列、图形)


如果还是不清楚到底怎么选择NoSQL,那就再详细说说每个类型的特点:

  1. 键值数据库:这个大家很熟悉,主要就是键值存储,代表=>Redis(支持持久化和数据恢复,后面我们会详谈)
  2. 文档数据库:代表=>MongoDB(优酷的在线评论就是用基于MongoDB的)
    1. 一般都不具备事务(MongoDB 4.0开始支持ACID事务了)
    2. 不支持Join(Value是一个可变的类JSON格式,表结构修改比较方便)
  3. 列式数据库:代表:CassandraHBase
    1. 对大量行少量列进行修改更新(新增一字段,批量做个啥操作的不要太方便啊~针对列为单位读写)
    2. 扩展性高,数据增加也不会降低对应的处理速度(尤其是写)
  4. 图形数据库:代表:Neo4J(数据模型是图结构的,主要用于 关系比较复杂 的设计,比如绘制一个QQ群关系的可视化图、或者绘制一个微博粉丝关系图等)


回头还是要把并发剩余几个专题深入的,认真看的同志会发现不管什么语言底层实现都是差不多的。

比如说进程,其底层就是用到了我们第一讲说的OS.fork。再说进(线)程通信,讲的PIPE、FIFO、Lock、Semaphore等很少用吧?但是Queue底层就是这些实现的,不清楚的话怎么读源码?

还记得当时引入Queue篇提到Java里的CountDownLatch吗?要是不了解Condition怎么自己快速模拟一个Python里面没有的功能呢?

知其然不知其所以然是万万不可取的。等后面讲MQ的时候又得用到Queue的知识了,可谓一环套一环~

既然不是公司的萌妹子,所以呢~技术的提升还是得靠自己了^_^,先到这吧,最后贴个常用解决方案:

Python、NetCore常用解决方案(持续更新)
https://github.com/LessChina


2.概念

上篇提到了ACID这次准备说说,然后再说说CAP和数据一致性

2.1.ACID事务

以小明和小张转账的例子继续说说:

  1. A:原子性(Atomic)

    • 小明转账1000给小张:小明-=1000 => 小张+=1000,这个 (事务)是一个不可分割的整体,如果小明-1000后出现问题,那么1000得退给小明
  2. C:一致性(Consistent)
    • 小明转账1000给小张,必须保证小明+小张的总额不变(假设不受其他转账(事务)影响)
  3. I:隔离性(Isolated)
    • 小明转账给小张的同时,小潘也转钱给了小张,需要保证他们相互不影响(主要是并发情况下的隔离)
  4. D:持久性(Durable)
    • 小明转账给小张银行要有记录,即使以后扯皮也可以拉流水账【事务执行成功后进行的持久化(就算数据库之后挂了也能通过Log恢复)】

2.2.CAP概念

CAP是分布式系统需要考虑的三个指标,数据共享只能满足两个而不可兼得:

  1. C:一致性(Consistency)

    • 所有节点访问同一份最新的数据副本(在分布式系统中的所有数据备份,在同一时刻是否同样的值)
    • eg:分布式系统里更新后,某个用户都应该读取最新值
  2. A:可用性(Availability)
    • 在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
    • eg:分布式系统里每个操作总能在一定时间内返回结果(超时不算【网购下单后一直等算啥?机房挂几个服务器也不影响】)
  3. P:分区容错性(Partition Toleranc)
    • 以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
    • eg:分布式系统里,存在网络延迟(分区)的情况下依旧可以接受满足一致性和可用性的请求

CA

代表:传统关系型数据库

如果想避免分区容错性问题的发生,一种做法是将所有的数据(与事务相关的)都放在一台机器上。虽然无法100%保证系统不会出错,但不会碰到由分区带来的负面效果(会严重的影响系统的扩展性)

作为一个分布式系统,放弃P,即相当于放弃了分布式,一旦并发性很高,单机服务根本不能承受压力。像很多银行服务,确确实实就是舍弃了P,只用高性能的单台小型机保证服务可用性。(所有NoSQL数据库都是假设P是存在的

CP

代表:ZookeeperRedis(分布式数据库、分布式锁)

相对于放弃“分区容错性“来说,其反面就是放弃可用性。一旦遇到分区容错故障,那么受到影响的服务需要等待数据一致等待数据一致性期间系统无法对外提供服务

AP

代表:DNS数据库IP和域名相互映射的分布式数据库,联想修改IP后为什么TTL需要10分钟左右保证所有解析生效)

反DNS查询:https://www.cnblogs.com/dunitian/p/5074773.html

放弃强一致,保证最终一致性。所有的NoSQL数据库都是介于CPAP之间,尽量往AP靠,(传统关系型数据库注重数据一致性,而对海量数据的分布式处理来说可用性和分区容错性优先级高于数据一致性)eg:

不同数据对一致性要求是不一样的,eg:

  1. 用户评论、弹幕这些对一致性是不敏感的,很长时间不一致性都不影响用户体验
  2. 像商品价格等等你敢来个看看?对一致性是很高要求的,容忍度铁定低于10s,就算使用了缓存在订单里面价格也是最新的(平时注意下JD商品下面的缓存说明,JD尚且如此,其他的就不用说了)

2.3.数据一致性

传统关系型数据库一般都是使用悲观锁的方式,但是例如秒杀这类的场景是hou不动,这时候往往就使用乐观锁了(CAS机制,之前讲并发和锁的时候提过),上面也稍微提到了不同业务需求对一致性有不同要求而CAP不能同时满足,这边说说主要就两种:

  1. 强一致性:无论更新在哪个副本上,之后对操作都要能够获取最新数据。多副本数据就需要分布式事物来保证数据一致性了(这就是问什么项目里面经常提到的原因)
  2. 最终一致性:在这种约束下保证用户最终能读取到最新数据。举几个例子:
    1. 因果一致性:A、B、C三个独立进程,A修改了数据并通知了B,这时候B得到的是最新数据。因为A没通知C,所以C不是最新数据
    2. 会话一致性:用户自己提交更新,他可以在会话结束前获取更新数据,会话结束后(其他用户)可能不是最新的数据(提交后JQ修改下本地值,不能保证数据最新)
    3. 读自写一致性:和上面差不多,只是不局限在会话中了。用户更新数据后他自己获取最新数据,其他用户可能不是最新数据(一定延迟)
    4. 单调读一致性:用户读取某个数值,后续操作不会读取到比这个数据还早的版本(新的程度>=读取的值)
    5. 单调写一致性(时间轴一致性):所有数据库的所有副本按照相同顺序执行所有更新操作(有点像RedisAOF

2.4.一致性实现方法

Quorum系统NRW策略(常用)

Quorum是集合A,A是全集U的子集,A中任意取集合B、C,他们两者都存在交集。

NRW算法

  1. N:表示数据所具有的副本数。
  2. R:表示完成读操作所需要读取的最小副本数(一次读操作所需参与的最小节点数)
  3. W:表示完成写操作所需要写入的最小副本数(一次写操作所需要参与的最小节点数)
  4. 只需要保证R + W > N就可以保证强一致性(读取数据的节点和被同步写入的节点是有重叠的)比如:N=3,W=2,R=2(有一个节点是读+写)

扩展

  1. 关系型数据库中,如果N=2,可以设置W=2,R=1(写耗性能一点),这时候系统需要两个节点上数据都完成更新才能确认结果并返回给用户
  2. 如果R + W <= N,这时候读写不会在一个节点上同时出现,系统只能保证最终一致性。副本达到一致性的时间依赖于系统异步更新的方式,不一致性时间=从更新节点~所有节点都异步更新完毕的耗时
  3. R和W设置直接影响系统的性能、扩展和一致性:
    1. 如果W设置为1,那么一个副本更新完就返回给用户,然后通过异步机制更新剩余的N-W个节点
    2. 如果R设置为1,只要有一个副本被读取就可以完成读操作,R和W的值如果较小会影响一致性,较大会影响性能
      • 当W=1,R=N==>系统对写要求高,但读操作会比较慢(N个节点里面有1个挂了,读就完成不了了)
      • 当R=1,W=N==>系统对读操作有高要求,但写性能就低了(N个节点里面有1个挂了,写就完成不了了)
    3. 常用方法:一般设置R = W = N/2 + 1,这样性价比高,eg:N=3,W=2,R=2(3个节点==>1写,1读,1读写

参考文章:

http://book.51cto.com/art/201303/386868.htm
https://blog.csdn.net/jeffsmish/article/details/54171812

时间轴策略(常用)

  1. 主要是关系型数据库的日记==>记录事物操作,方便数据恢复
  2. 还有就是并行数据存储的时候,由于数据是分散存储在不同节点的,对于同一节点来说只要关心数据更新+消息通信(数据同步):
    • 保证较晚发生的更新时间>较早发生的更新时间
    • 消息接收时间 > 消息发送时刻的时间(要考虑服务器时间差的问题~时间同步服务器)

其他策略

其实还有很多策略来保证,这些概念的对象逆天不是很熟~比如:向量时钟策略

推荐几篇文章

https://www.cnblogs.com/yanghuahui/p/3767365.html
http://blog.chinaunix.net/uid-27105712-id-5612512.html
https://blog.csdn.net/dellme99/article/details/16845991
https://blog.csdn.net/blakeFez/article/details/48321323

原文地址:https://www.cnblogs.com/dotnetcrazy/p/9690466.html

时间: 2024-10-18 14:21:49

聊聊数据库~开篇的相关文章

聊聊数据库级联删除与伪删除的设计方案

背景: 这两天看了重温了下设计模式和数据结构,又补了下基础知识,然后就失眠了一整夜,不知为啥就想到级联及伪删数据这个问题. 由于级联删除是几乎人人都会遇到的问题,但方案却有限却不美好,所以欢迎大伙集思文益,以下内容欢迎大伙一起讨论. 级联删除的方式: 方式1:数据库设定级联: 常规MSSQL.MySql.Oracle都对设定了主外键关系的表提供级联删除. 优点:数据准确.使用方便,数据库设计之初就设定好. 缺点: 1:增加对增删改时外键检测的额外开销. 2:潜在危险系素大(如:删除部门或角色,发

Mysql学习笔记(四)聊聊数据库索引

小心情(可直接跳到分割线后) 今天心情好些了.一些浓的化不开的坏情绪,也渐渐的在晚上解决掉一个复杂的逻辑问题后,渐渐消散了. 今天中午去吃饭的时候,坤哥漫不经心的说:'我这么多年终于悟出了一个道理,人年轻的时候不要那么拼命,都没有时间做其他事情了' 我问什么其他事情,坤哥看了我一眼,又继续漫不经心的说,那么忙,都没有时间谈恋爱了. 我想不那么拼命可以嘛?房价每年都涨,生活的成本与日俱增.如果不努力让自己的价值所赚取的金钱,超过经济增速.那么只能继续成为一个社会底层的loser,继续在青春的美好时

聊聊数据库乐观锁和悲观锁,乐观锁失败后重试

在写入数据库的时候需要有锁,比如同时写入数据库的时候会出现丢数据,那么就需要锁机制. 数据锁分为乐观锁和悲观锁,那么它们使用的场景如下: 1. 乐观锁适用于写少读多的情景,因为这种乐观锁相当于JAVA的CAS,所以多条数据同时过来的时候,不用等待,可以立即进行返回. 2. 悲观锁适用于写多读少的情景,这种情况也相当于JAVA的synchronized,reentrantLock等,大量数据过来的时候,只有一条数据可以被写入,其他的数据需要等待.执行完成后下一条数据可以继续. 他们实现的方式上有所

基于 EntityFramework 的数据库主从读写分离架构(2)- 改进配置和添加事务支持

回到目录,完整代码请查看(https://github.com/cjw0511/NDF.Infrastructure)中的目录: src\ NDF.Data.EntityFramework\MasterSlaves 上一回中(http://www.cnblogs.com/cjw0511/p/4398267.html),我们简单讲述了基于 EF 来实现数据库读写分离的原理.当然,这只是一个 demo 级别的简单实现,实际上,在我们工作环境中,碰到的情况远比这复杂多了,例如数据库连接的配置是通过 c

redis 数据库主从不一致问题解决方案

在聊数据库与缓存一致性问题之前,先聊聊数据库主库与从库的一致性问题. 问:常见的数据库集群架构如何? 答:一主多从,主从同步,读写分离. 如上图: (1)一个主库提供写服务 (2)多个从库提供读服务,可以增加从库提升读性能 (3)主从之间同步数据 画外音:任何方案不要忘了本心,加从库的本心,是提升读性能. 问:为什么会出现不一致? 答:主从同步有时延,这个时延期间读从库,可能读到不一致的数据. 如上图: (1)服务发起了一个写请求 (2)服务又发起了一个读请求,此时同步未完成,读到一个不一致的脏

信安周报-第02周:SQL基础

信安之路 第02周 Code:https://github.com/lotapp/BaseCode/tree/master/safe 前言 本周需要自行研究学习的任务贴一下: 1.概念(推荐) 数据库系列去年就开始陆陆续续的发文,这周任务简单带过,概念部分我更新了一下,其他部分看扩展吧~ 1.1.关系型数据库 引用百科的一段抽象描述: "关系型数据库,是指采用了关系模型来组织数据的数据库,其以行和列的形式存储数据,以便于用户理解,关系型数据库这一系列的行和列被称为表,一组表组成了数据库.用户通过

上周热点回顾(7.25-7.31)

热点随笔: · [无私分享:从入门到精通ASP.NET MVC]从0开始,一起搭框架.做项目 (14)附数据库.发布项目(果冻布丁喜之郎)· [无私分享:ASP.NET CORE 项目实战(第四章)]Code First 创建数据库和数据表(果冻布丁喜之郎)· 十分钟玩转 jQuery.实例大全(索宁)· 绝对公平?破解北京机动车摇号的秘密(FerventDesert)· .Net中的AOP系列之构建一个汽车租赁应用(tkb至简)· 数据库优化案例——————某市中心医院HIS系统(Double

万物互联之~RPC专栏

其他专栏最新篇:协程加强之~兼容答疑篇 | 聊聊数据库~SQL环境篇 上篇回顾:万物互联之~深入篇 3.RPC引入 Code:https://github.com/lotapp/BaseCode/tree/master/python/6.net/6.rpc/ 3.1.概念 RPC(Remote Procedure Call):分布式系统常见的一种通信方法(远程过程调用),通俗讲:可以一台计算机的程序调用另一台计算机的子程序(可以把它看成之前我们说的进程间通信,只不过这一次的进程不在同一台PC上了

万物互联之~网络编程深入篇

深入篇¶ 上节回顾:5种IO模型 | IO多路复用 and 万物互联之-网络编程加强篇 官方文档:https://docs.python.org/3/library/internet.html 1.概念回顾¶ 1.1.TCP三次握手¶ 画一张图来通俗化讲讲TCP三次握手: 用代码来说,大概过程就是: 1.2.TCP四次挥手¶ 画图通俗讲下TCP四次挥手: 用代码来说,大概过程就是: 其实这个也很好的解释了之前的端口占用问题,如果是服务端先断开连接,那么服务器就是四次挥手的发送方,最后一次消息是得