数据库与存储系统 | 青训营笔记

72 阅读4分钟

这是我参与[第五届青训营]伴学笔记创作活动的第11天

  1. 存储 & 数据库简介
  2. 主流产品剖析
  3. 课后思考

数据库简介

存储系统- 数据是怎么从应用到存储介质的?

  • 缓存:很重要,贯穿整个存储体系

  • 拷贝和昂贵,应该尽量减少

    存储系统-RAID技术

关系型数据库事务的特点,以MySQL为例

  • 原子性:事务是最小的单元,不可分割
  • 一致性:要不同时执行,要不同时失败
  • 隔离性:两个事务之间会有隔离性,就像是一道墙
  • 持久性:事务提交后会持久保存在磁盘里

非关键型数据库和关系型数据库有什么区别?

关系型数据库中最典型的数据结构就是表

  • 优点:易于维护:都是使用表结构 使用方便:通用sql语句,可用于复杂查询
  • 缺点:读写性能差 灵活度差

非关系型数据库

  • 优点:使用灵活,应用广泛(存储数据可以是key value的形式、文档形式、图片形式等等) 速度快(可以以硬盘或者存储器作为载体) 高扩展性 成本低(部署方便)
  • 缺点 :不提sql支持 学习和使用成本高 无事务处理 数据结构相对复杂

主流产品

单机存储产品

  • 单机文件系统
  • 单机文件系统

分布式存储产品

  • HDFS
  • Ceph

单机数据库产品

  • 关系型数据库 —— PG、MySQL
  • 非关系型数据库 —— ES、MongoDB、Redis

分布式数据库产品

课后思考

问题1:写入存储系统的粒度太大,会不会导致数据原子性问题?例如一次性写100MB,如果系统突然crash,会不会只有一部分数据持久化了,另一部分丢失了?如果要解决原子性问题,一般会设计什么机制?

问题2:一个关系型数据库大概率是会被并发访问的,如果要保证并发安全,除了在行数据上加悲观锁还有其他方式吗?

首先加锁方式有两种:乐观锁和悲观锁。区别如下:

乐观锁:觉得不太可能会产生并发冲突去完成某项操作,也就是不加锁,在事务提交的时候检测期间是否存在并发冲突,如果有则返回错误,让用户决定如何去做

实现方式:CAS(多个线程会自旋,适用于资源争抢少)

悲观锁:总是假设会产生并发冲突(总有刁民想害朕),会在操纵的过程中就加锁,其他请求无法操作(多个线程会挂起,然后唤醒,适用于资源多,资源多进行自旋会非常浪费cpu)

实现方式:Java程序中的Synchronized和ReentrantLock等实现的锁也均为悲观锁。

延伸:lock锁和synchronized锁的区别?

Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;

synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;

Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;

通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。

Lock可以提高多个线程进行读操作的效率。(可以通过readwritelock实现读写分离)

性能上来说,在资源竞争不激烈的情形下,Lock性能稍微比synchronized差点(编译程序通常会尽可能的进行优化synchronized)。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。

lock里面又有好几个接口和类,它们里面方法又有各自的不同,可以参考这篇文章并发编程的锁机制:synchronized和lock - 掘金 (juejin.cn)