这是我参与[第五届青训营]伴学笔记创作活动的第11天
- 存储 & 数据库简介
- 主流产品剖析
- 课后思考
数据库简介
存储系统- 数据是怎么从应用到存储介质的?
-
缓存:很重要,贯穿整个存储体系
-
拷贝和昂贵,应该尽量减少
存储系统-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)