数据库基本知识

感觉面试的时候面试官大多数都必问数据库,也可以理解,企业肯定会涉及到大规模数据存储,那么数据库存储就一定会用到数据库。做一些数据库相关的基本知识总结,持续更新~

【死锁专题】

1.如何解决数据库并发造成的安全问题(想让你说一些关于锁的知识)

        ①事务管理:使用数据库管理系统提供的事务管理功能。事务可以确保一组操作要么全部成功提交,要么全部失败回滚,从而保证数据的一致性和完整性

        ②加锁:使用适当的锁机制来控制并发访问。提供锁定数据行、表或其他资源,防止多个数据对同一资源进行修改,从而避免数据不一致性。

        eg:使用乐观或悲观并发控制机制,乐观并发控制通常基于版本控制或时间戳,允许多个事务同时读取数据,但写入时检查是否有冲突。悲观并发控制则是在访问数据时先获取锁,确保凄然事务无法修改。

        ③隔离级别:设置适当的事务隔离级别,以控制并发事务之间的可见性和影响范围。常见的隔离级别包括读未提交、读已提交、可重复读和串行化,可以根据应用需求选择。

        ④异常处理:编写异常处理模块抛出异常确保系统的稳定性和可靠性(这条说不说都行吧,感觉三条就够了)

2.数据库的死锁是什么

        加锁(Locking)是数据库在并发访问时保证数据一致性和完整性的主要机制。任何事务都需要获得相应对象上的锁才能访问数据,读取数据的事务通常只需要获得读锁(共享锁),修改数据的事务需要获得写锁(排他锁)。当两个事务互相之间需要等待对方释放获得的资源时,如果系统不进行干预则会一直等待下去,也就是进入了死锁(deadlock)状态。

3.如何解决死锁状态

        死锁不是数据库自身的问题,我们无法通过优化数据库配置来解决或者避免死锁,只能通过修改应用程序来解决。也可以捕获系统返回的死锁异常并在程序中加入重试机制。

4.常见的死锁原因与解决方案有:

        1. 事务之间对资源访问顺序的交替

        出现原因: 
        一个用户A 访问表A(锁住了表A),然后又访问表B;另一个用户B 访问表B(锁住了表B),然后企图访问表A;这时用户A由于用户B已经锁住表B,它必须等待用户B释放表B才能继续,同样用户B要等用户A释放表A才能继续,这就死锁就产生了。

        解决方法: 
        这种死锁比较常见,是由于程序的BUG产生的,除了调整的程序的逻辑没有其它的办法。仔细分析程序的逻辑,对于数据库的多表操作时,尽量按照相同的顺序进行处理,尽量避免同时锁定两个资源,如操作A和B两张表时,总是按先A后B的顺序处理, 必须同时锁定两个资源时,要保证在任何时刻都应该按照相同的顺序来锁定资源

        2. 并发修改同一记录

        出现原因:主要是由于没有一次性申请够权限的锁导致的。参考:记录一次死锁排查过程

        用户A查询一条纪录,然后修改该条纪录;这时用户B修改该条纪录,这时用户A的事务里锁的性质由查询的共享锁企图上升到独占锁,而用户B里的独占锁由于A有共享锁存在所以必须等A释放掉共享锁,而A由于B的独占锁而无法上升的独占锁也就不可能释放共享锁,于是出现了死锁。这种死锁比较隐蔽,但在稍大点的项目中经常发生。 

        解决方法:

        a. 乐观锁,实现写-写并发

        b. 悲观锁:使用悲观锁进行控制。悲观锁大多数情况下依靠数据库的锁机制实现,如Oracle的Select … for update语句,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。

        3. 索引不当导致的死锁

        出现原因: 
        如果在事务中执行了一条不满足条件的语句,执行全表扫描,把行级锁上升为表级锁,多个这样的事务执行后,就很容易产生死锁和阻塞。类似的情况还有当表中的数据量非常庞大而索引建的过少或不合适的时候,使得经常发生全表扫描,最终应用系统会越来越慢,最终发生阻塞或死锁。

        另外一种情况是由于二级索引的存在,上锁的顺序不同导致的,这部分在讨论索引时会提到。参考:https://www.cnblogs.com/LBSer/p/5183300.html

        解决方法:

        SQL语句中不要使用太复杂的关联多表的查询;使用“执行计划”对SQL语句进行分析,对于有全表扫描的SQL语句,建立相应的索引进行优化。

5.如何尽量避免死锁

        1)以固定的顺序访问表和行。即按顺序申请锁,这样就不会造成互相等待的场面。

        2)大事务拆小。大事务更倾向于死锁,如果业务允许,将大事务拆小。

        3)在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁概率。

        4)降低隔离级别。如果业务允许,将隔离级别调低也是较好的选择,比如将隔离级别从RR调整为RC,可以避免掉很多因为gap锁造成的死锁。

        5)为表添加合理的索引。如果不走索引将会为表的每一行记录添加上锁,死锁的概率大大增大。

补充,操作系统中的死锁:

 死锁产生的四个必要条件:互斥、请求与保持、不可剥夺、循环等待

预防死锁:除了不可以破坏互斥条件的三个破坏

避免死锁:银行家算法

        银行家算法,每一个新进程在进系统时,它必须申明在运行过程中,可能需要每种资源类型的最大单元数目,其数目不应超过系统所拥有的资源总量。当进程请求一组资源时,系统必须首先确定是否有足够的资源分配给该进程。如果有,再进一步运算将资源分配给该进程后,是否会使系统处于不安全状态。如果不会,才将资源分配给该进程。

【设计专题】

教亿级消息接收处理策略的问题?大致需要怎么设计来满足需求?限于资源情况,主要只能考虑用kafka、redis、mysql。

问题简述:一个应用系统A 需要通过HTTP接口接收某外部系统B的消息,系统A 提供3个接口,接收来自系统B的三类消息,每月数据总量约150亿条,经处理后推送前端。请问如何设计

答:可以设计一个使用 MySQL 存储核心数据,Redis 作为缓存层提高数据访问速度并防止缓存击穿,以及 Kafka 处理实时数据流的混合架构。

  1. MySQL 做数据库
    • MySQL 是一种广泛使用的关系型数据库管理系统(RDBMS)。它用于存储结构化数据,支持复杂的查询操作,事务处理,以及数据的持久化存储。在这个场景中,MySQL 负责存储应用的核心数据,如用户信息、订单数据等。
  2. Redis 做缓存和防止缓存击穿
    • Redis 是一个高性能的键值对存储系统,支持多种类型的数据结构,如字符串、哈希、列表、集合、有序集合等。它通常用作缓存层,以减少对数据库的访问次数,提高数据访问速度。
    • 缓存存储:虽然 Redis 本身不提供传统数据库中的索引功能(如 B-Tree 索引),但它可以通过其数据结构(如有序集合)来模拟某些类型的索引功能,帮助快速查找数据,更常见的是使用 Redis 存储频繁访问的数据或热点数据。
    • 防止缓存击穿:缓存击穿是指当缓存中没有但数据库中有的数据(缓存项失效或从未被缓存)被大量并发请求时,这些请求都会穿透到数据库,导致数据库压力骤增。Redis 可以通过设置合理的缓存过期策略、使用布隆过滤器等技术来减少或避免缓存击穿的发生。
  3. Kafka 处理流式能力
    • Kafka 是一个分布式流处理平台,它主要用于构建实时数据管道和流应用程序。Kafka 提供了高吞吐量、可扩展性、容错性等特点,非常适合处理大规模数据流。
    • 在这个场景中,Kafka 可以用于处理来自各种数据源(如用户行为、传感器数据等)的实时数据流。通过 Kafka,可以实时地收集、处理、分析和分发这些数据,为应用提供实时的数据洞察和决策支持。

Kafka可以作为数据流处理系统中的缓冲区,收集并暂存大量数据,供后续处理系统使用,这主要得益于其高吞吐量、低延迟和可扩展性的特性。然而,尽管Kafka在数据存储和传输方面表现出色,但它通常不被视为一个全面的数据库系统,这主要是因为它在设计初衷、功能特性和使用场景上与传统的数据库系统存在显著差异。

为什么Kafka不能当数据库?

  1. 数据模型和设计目标
    • Kafka是一个分布式流处理平台,其设计目标是提供高吞吐量、低延迟的数据传输。它专注于数据的实时处理和分发,而不是作为长期存储或复杂查询的数据库。
    • 相比之下,数据库系统(如MySQL)具有更丰富的数据模型,支持复杂的查询、事务处理、数据完整性约束等功能,旨在满足各种数据管理和分析需求。
  2. 查询和索引能力
    • Kafka没有像传统数据库那样的查询语言和索引机制。虽然Kafka可以通过一些工具和扩展(如ksqlDB)来实现一定的查询能力,但这与成熟的数据库系统相比仍有较大差距。
    • 数据库系统通过索引和查询优化技术,可以高效地处理复杂的查询请求,而Kafka则更侧重于数据的快速写入和分发。
  3. 事务和一致性保证
    • Kafka在事务处理和数据一致性方面提供了一定程度的支持,但与传统数据库相比仍有一定限制。例如,Kafka的事务处理主要关注于生产者发送消息到多个分区时的一致性,而不是像数据库那样提供全面的ACID(原子性、一致性、隔离性、持久性)事务支持。
    • 数据库系统通过严格的事务控制和隔离级别,确保数据的一致性和完整性,这对于需要高可靠性的应用场景至关重要。
  4. 持久化和存储管理
    • Kafka将数据持久化到磁盘上,并提供数据复制和容错机制以确保数据的可靠性和可用性。然而,它的存储管理机制相对简单,主要关注于日志文件的组织和管理。
    • 数据库系统则具有更复杂的存储管理机制,包括表空间、数据文件、索引文件等的组织和管理,以及更精细的存储参数调整和优化能力。
  5. 使用场景和定位
    • Kafka主要适用于大数据处理、日志收集、消息通知和实时数据分析等场景,作为数据流处理系统中的关键组件之一。
    • 而数据库系统则更广泛地应用于各种需要数据管理和分析的应用场景中,包括Web应用、企业应用、数据分析等。

Kafka侧重于数据的快速写入和分发,这一特点在其设计中得到了多方面的支持,主要体现在以下几个方面:

1. 分布式架构和分区策略

  • 分布式架构:Kafka采用分布式架构,能够跨多个节点进行数据的存储和处理。这种设计使得Kafka能够轻松地进行水平扩展,通过增加更多的节点来提高系统的处理能力和吞吐量。
  • 分区策略:Kafka将每个主题(Topic)划分为多个分区(Partition),每个分区都是一个有序的消息队列。这些分区可以分布在不同的节点上,实现了数据的并行处理。通过增加分区数量,可以进一步提高系统的并发处理能力。

2. 顺序写入和零拷贝技术

  • 顺序写入:Kafka采用顺序写入的方式将数据追加到磁盘文件的末尾,这种写入方式大大减少了磁盘I/O操作的次数,提高了写入效率。顺序写入比随机写入具有更高的性能,因为磁盘在顺序读写时能够更有效地利用缓存和减少寻道时间。
  • 零拷贝技术:Kafka在数据传输过程中使用了零拷贝技术,减少了数据在内存中的拷贝次数,进一步提高了数据传输的效率。零拷贝技术允许操作系统直接将数据从磁盘传输到网络,而无需通过应用程序的缓冲区,从而减少了CPU的负载和提高了数据传输的速率。

3. 高效利用磁盘和内存

  • 磁盘缓存:Kafka充分利用了现代操作系统提供的磁盘缓存机制,将频繁访问的数据缓存在内存中,以减少对磁盘的直接访问。这种机制不仅提高了数据读取的效率,还减少了磁盘的磨损。
  • 内存映射文件:Kafka使用内存映射文件(Memory-Mapped Files)来管理磁盘上的数据。通过将磁盘文件映射到进程的地址空间中,Kafka可以直接通过内存来访问磁盘上的数据,而无需进行额外的读写操作。这种方式不仅提高了数据的访问速度,还简化了代码逻辑。

4. 可扩展性和容错性

  • 可扩展性:Kafka的分布式架构和分区策略使得其能够轻松地进行水平扩展。通过增加更多的节点和分区,可以进一步提高系统的处理能力和吞吐量,满足不断增长的数据处理需求。
  • 容错性:Kafka通过副本机制来确保数据的可靠性和容错性。每个分区都有多个副本分布在不同的节点上,当某个节点发生故障时,其他副本可以接管其工作,确保数据不会丢失。这种机制保证了Kafka在高负载和故障情况下的稳定性和可用性。

Redis为何不能用作数据库

  1. 数据持久化能力限制
    • Redis虽然提供了RDB(快照)和AOF(日志)两种持久化方式,但这些方式相比传统的数据库系统来说功能较为简单,且存在一定的缺陷。RDB在发生故障时可能导致一部分数据的丢失,而AOF则可能因为频繁的写操作导致文件过大,影响性能。
    • 传统的关系型数据库如MySQL等,能够提供更复杂和可靠的数据持久化机制,确保数据的安全性和可靠性。
  2. 事务处理和ACID特性
    • Redis虽然支持事务处理,但并不完全支持ACID(原子性、一致性、隔离性、持久性)特性。在处理复杂的数据操作和事务时,Redis存在一定的限制。
    • 相比之下,传统的数据库系统通过严格的事务控制和隔离级别,能够确保数据的一致性和完整性。
  3. 查询和索引能力
    • Redis主要作为一个键值对存储系统,其查询能力相对有限。虽然Redis支持一些复杂的数据结构如列表、集合和有序集合等,但相比传统数据库的复杂查询语言(如SQL)来说,Redis的查询能力较为简单。
    • 传统数据库系统提供了丰富的查询语言和索引机制,能够高效地处理复杂的查询请求。

Redis为何主要用于缓存

  1. 高性能
    • Redis是一个基于内存的数据存储系统,其读写速度非常快。相比传统的关系型数据库,Redis能够提供更高的性能和吞吐量。这使得Redis非常适合用作缓存,可以显著提升应用程序的响应速度和吞吐量。
  2. 灵活的数据结构
    • Redis不仅仅是一个简单的键值存储系统,它还支持丰富的数据结构如字符串、哈希表、列表、集合和有序集合等。这些数据结构使得Redis能够适用于各种应用场景,并简化了应用程序的开发过程。
  3. 持久化支持
    • 尽管Redis是一个基于内存的数据库,但它提供了持久化的支持。通过将数据保存到磁盘上,Redis可以在服务器重启后快速恢复数据,并可以根据需求进行灵活的配置以平衡性能和数据安全性。
  4. 高可用性
    • Redis提供了主从复制和集群功能,可以实现数据的备份和故障恢复。这些功能提高了Redis的可用性和容错能力,使得Redis在缓存场景中更加可靠。

支持这些特点的设计因素

  • 内存存储:Redis将数据存储在内存中,这使得其读写速度非常快。同时,Redis也提供了持久化机制以应对内存数据易失性的问题。
  • 数据结构丰富性:Redis支持多种数据结构,这些数据结构的设计使得Redis能够灵活地应对各种应用场景。
  • 高效的数据结构和算法:Redis通过优化数据结构和算法来提高性能和并发处理能力。例如,Redis使用哈希表来实现快速的键值查找和更新操作。
  • 分布式和集群支持:Redis提供了分布式和集群功能,以支持大规模和高可用性的部署。这使得Redis能够应对高并发和大数据量的挑战。

尽管MySQL是一款优秀的关系型数据库管理系统,但它在某些方面仍然存在局限性,这就是为什么还需要Redis和Kafka等系统作为补充的原因。以下是具体的分析:

Redis的补充作用

(1)性能差异

  • 内存存储:Redis是一个基于内存的键值对存储系统,其数据主要存储在内存中,因此读写速度非常快。相比之下,MySQL的数据存储在磁盘上,虽然通过索引和优化可以提高查询效率,但在处理高并发读写请求时,磁盘I/O可能成为瓶颈。
  • 数据类型丰富:Redis支持多种数据类型,如字符串、列表、哈希表、集合和有序集合等,这些数据类型使得Redis能够灵活地处理各种数据结构,满足复杂的数据操作需求。

(2)缓存功能

  • 缓存层:Redis常被用作MySQL的缓存层,用于存储热点数据或临时数据。通过将频繁访问的数据存储在Redis中,可以减少对MySQL的访问次数,降低MySQL的压力,提高系统的整体性能。

(3)高可用性和持久化

  • 主从复制和分布式:Redis支持主从复制和分布式部署,可以实现数据的高可用性和容错性。即使某个节点出现故障,其他节点也能继续提供服务,保证数据的可靠性和连续性。
  • 持久化机制:Redis提供了RDB和AOF两种持久化方式,可以将内存中的数据定期写入磁盘,以防止数据丢失。

Kafka的补充作用

(1)实时数据处理

  • 分布式消息队列:Kafka是一个分布式消息队列系统,具有高吞吐量、低延迟和可扩展性等特点。它能够实现数据的快速写入和分发,满足实时数据处理和流处理的需求。

(2)解耦和缓冲

  • 解耦系统:Kafka可以在系统之间提供松耦合的通信方式。生产者将数据发送到Kafka中,消费者从Kafka中拉取数据进行处理,这样生产者和消费者之间就不需要直接通信,降低了系统的耦合度。
  • 缓冲压力:Kafka可以作为消息队列,在系统之间缓冲数据流量,避免高峰时期数据拥堵导致的系统崩溃。

(3)数据持久化和可靠性

  • 数据持久化:Kafka将消息存储在磁盘上,并提供多种数据复制和容错机制,确保数据的可靠性和持久性。
  • 事务支持和消息确认:Kafka支持事务处理和消息确认机制,可以确保消息的正确传递和处理。

综上所述,Redis和Kafka在性能、缓存、实时数据处理、解耦和缓冲、数据持久化和可靠性等方面为MySQL提供了重要的补充作用。它们各自具有独特的特点和优势,可以根据实际业务需求进行选择和组合使用,以构建高效、可靠、可扩展的数据处理系统。

参考文章:

数据库死锁及解决方法 - wezheng - 博客园 (cnblogs.com)

5 分钟理解数据库死锁_sql error: 1205, sqlstate: 40001-CSDN博客

计算机操作系统——死锁(产生的必要条件与处理死锁的四个关卡)_操作系统中必要条件请求与保持-CSDN博客

  • 26
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值