先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Golang全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024b (备注go)
正文
在关系型数据库中,实体以及实体间的联系均由单一的结构类型来表示,这种逻辑结构是一张二维表。图 1 所示的学生选课系统中,实体和实体间联系在数据库中的逻辑结构可通过图 2 所示。
图 1:关系型数据库
图 2:学生选课系统数据库逻辑结构
关系型数据库以行和列的形式存储数据,这一系列的行和列被称为表,一组表组成了数据库。图 3 所示的员工信息表就是关系型数据库。
图 3:员工信息表
属性说明:
- 二维表:也称为关系,它是一系列二维数组的集合,用来代表与存储数据对象之间的关系。它由纵向的列和横向的行组成。
- 行:也叫元组或记录,在表中是一条横向的数据集合,代表一个实体。
- 列:也叫字段或属性,在表中是一条纵行的数据集合。列也定义了表中的数据结构。
- 主属性:关系中的某一属性组,若它们的值唯一地标识一个记录,则称该属性组为主属性或主键。主属性可以是一个属性,也可以由多个属性共同组成。在图 1-5 中,学号是学生信息表的主属性,但是课程信息表中,学号和课程号共同唯一地标识了一条记录,所以学号和课程号一起组成了课程信息表的主属性。
结构化查询语言
关系型数据库的核心是其结构化的查询语言(Structured Query Language, SQL),SQL 涵盖了数据的查询、操纵、定义和控制,是一个综合的、通用的且简单易懂的数据库管理语言。同时 SQL 又是一种高度非过程化的语言,数据库管理者只需要指出做什么,而不需要指出该怎么做即可完成对数据库的管理。
SQL 可以实现数据库全生命周期的所有操作,所以 SQL 自产生之日起就成了检验关系型数据库管理能力的“试金石”,SQL 标准的每一次变更和完善都引导着关系型数据库产品的发展方向。
SQL 包含以下四个部分。
数据定义语言(DDL)
DDL 包括 CREATE、DROP、ALTER 等动作。在数据库中使用 CREATE 来创建新表,DROP 来删除表,ALTER 负责数据库对象的修改。
例如,创建学生信息表使用以下命令:
CREATE TABLE StuInfo(id int(10) NOT NULL,PRIMARY KEY(id),name varchar(20), female bool,class varchar(20));
数据查询语言(Data Query Language, DQL)
DQL 负责进行数据查询,但是不会对数据本身进行修改。
DQL的语法结构如下:
SELECT FROM 表名1,表2
where 查询条件 #可以组合 and、or、 not、 =、between、and、in、like 等;
group by 分组字段
having (分组后的过滤条件)
order by 排序字段和规则;
数据操纵语言(Data Manipulation Language, DML)
DML 负责对数据库对象运行数据访问工作的指令集,以 INSERT、UPDATE、DELETE 三种指令为核心,分别代表插入、更新与删除。
向表中插入数据命令如下:
INSERT 表名 (字段1,字段2,…,字段n,) VALUES (字段1值,字段2值,…,字段n值) where 查询条件;
数据控制语言(Data Control Language, DCL)
DCL 是一种可对数据访问权进行控制的指令。它可以控制特定用户账户对查看表、预存程序、用户自定义函数等数据库操作的权限,由 GRANT 和 REVOKE 两个指令组成。
DCL 以控制用户的访问权限为主,GRANT 为授权语句,对应的 REVOKE 是撤销授权语句。
关系型数据库的优缺点
关系型数据库已经发展了数十年,其理论知识、相关技术和产品都趋于完善,是目前世界上应用最广泛的数据库系统。
关系型数据库的优点
- 容易理解:二维表结构非常贴近逻辑世界的概念,关系型数据模型相对层次型数据模型和网状型数据模型等其他模型来说更容易理解。
- 使用方便:通用的 SQL 使用户操作关系型数据库非常方便。
- 易于维护:丰富的完整性大大减少了数据冗余和数据不一致的问题。关系型数据库提供对事务的支持,能保证系统中事务的正确执行,同时提供事务的恢复、回滚、并发控制和死锁问题的解决。
关系型数据库的缺点
随着各类互联网业务的发展,关系型数据库难以满足对海量数据的处理需求,存在以下不足。
- 高并发读写能力差:网站类用户的并发性访问非常高,而一台数据库的最大连接数有限,且硬盘 I/O 有限,不能满足很多人同时连接。
- 对海量数据的读写效率低:若表中数据量太大,则每次的读写速率都将非常缓慢。
- 扩展性差:在一般的关系型数据库系统中,通过升级数据库服务器的硬件配置可提高数据处理的能力,即纵向扩展。但纵向扩展终会达到硬件性能的瓶颈,无法应对互联网数据爆炸式增长的需求。还有一种扩展方式是横向扩展,即采用多台计算机组成集群,共同完成对数据的存储、管理和处理。这种横向扩展的集群对数据进行分散存储和统一管理,可满足对海量数据的存储和处理的需求。但是由于关系型数据库具有数据模型、完整性约束和事务的强一致性等特点,导致其难以实现高效率的、易横向扩展的分布式架构。
NoSQL数据库的优势有哪些?
数据是当今世界最有价值的资产之一。在大数据时代,人们生产、收集数据的能力大大提升,但是传统的关系型数据库在可扩展性、数据模型和可用性方面已远远不能满足当前的数据处理需求,因此,各种 NoSQL 数据库系统应运而生。
NoSQL 数据库不像关系型数据库那样都有相同的特点,遵循相同的标准。NoSQL 数据库类型多样,可满足不同场景的应用需求,因此取得了巨大的成功。
NoSQL 数据库基本理念是以牺牲事务机制和强一致性机制,来获取更好的分布式部署能力和横向扩展能力,创造出新的数据模型,使其在不同的应用场景下,对特定业务数据具有更强的处理性能。
NoSQL 数据库最初是为了满足互联网的业务需求而诞生的,互联网数据具有大量化、多样化、 快速化等特点。
在信息化时代背景下,互联网数据增长迅猛,数据集合规模已实现从 GB、PB 到 ZB 的飞跃。数据不仅仅是传统的结构化数据,还包含了大量的非结构化和半结构化数据,关系型数据库无法存储此类数据。
因此,很多互联网公司着手研发新型的、非关系型的数据库,这类非关系型数据库统称为 NoSQL 数据库,其主要优势如下。
灵活的数据模型
互联网数据如网站用户信息、地理位置数据、社交图谱、用户产生的内容、机器日志数据以及传感器数据等,正在快速改变着人们的通信、购物、广告、娱乐等日常生活,没有使用这些数据的应用很快就会被用户所遗忘。开发者希望使用非常灵活的数据库,容纳新的数据类型,并且不会被第三方数据提供商的数据结构变化所影响。
关系型数据库的数据模型定义严格,无法快速容纳新的数据类型。例如,若要存储客户的电话号码、姓名、地址、城市等信息,则 SQL 数据库需要提前知晓要存储的是什么。这对于敏捷开发模式来说十分不方便,因为每次完成新特性时,通常都需要改变数据库的模式。
NoSQL 数据库提供的数据模型则能很好地满足这种需求,各种应用可以通过这种灵活的数据模型存储数据而无须修改表;或者只需增加更多的列,无须进行数据的迁移。
可伸缩性强
对企业来说,关系型数据库一开始是普遍的选择。然而,在使用关系型数据库的过程中却遇到了越来越多的问题,原因在于它们是中心化的,是纵向扩展而不是横向扩展的。这使得它们不适合那些需要简单且动态可伸缩性的应用。
NoSQL 数据库从一开始就是分布式、横向扩展的,因此非常适合互联网应用分布式的特性。
在互联网应用中,当数据库服务器无法满足数据存储和数据访问的需求时,只需要增加多台服务器,将用户请求分散到多台服务器上,即可减少单台服务器的性能瓶颈出现的可能性。
自动分片
由于关系型数据库存储的是结构化的数据,所以通常采用纵向扩展,即单台服务器要持有整个数据库来确保可靠性与数据的持续可用性。这样做的代价是非常昂贵的,而且扩展也会受到限制。针对这种问题的解决方案就是横向扩展,即添加服务器而不是扩展单台服务器的处理能力。
NoSQL 数据库通常都支持自动分片,这意味着它们会自动地在多台服务器上分发数据,而不需要应用程序增加额外的操作。
自动复制
NoSQL 数据库支持自动复制。在 NoSQL 数据库分布式集群中,服务器会自动对数据进行备份,即将一份数据复制存储在多台服务器上。因此,当多个用户访问同一数据时,可以将用户请求分散到多台服务器中。
同时,当某台服务器岀现故障时,其他服务器的数据可以提供备份,即 NoSQL 数据库的分布式集群具有高可用性与灾备恢复的能力。
分布式数据库有哪些特点?
大数据需要通过分布式的集群方式来解决存储和访问的问题。分布式系统的核心理念是让多台服务器协同工作,完成单台服务器无法处理的任务,尤其是高并发或者大数据量的任务。
分布式数据库是数据库技术与网络技术相结合的产物,它通过网络技术将物理上分开的数据库连接在一起,进行逻辑层面上的集中管理。
在分布式数据库系统中,一个应用程序可以对数据库进行透明操作,数据库中的数据分别存储在不同的局部数据库中,由不同机器上不同的 DBMS 进行管理,其的体系结构如下图所示。
分布式数据处理使用分而治之的办法来解决大规模数据管理问题,它处理数据的基本特点如下。
分布的透明管理
在分布式系统中,数据不是存储在一个场地上,而是存储在计算机网络的多个场地上。但逻辑上是一个整体,它们被所有用户共享,并由一个 DBMS 统一管理。用户访问数据时无须指出数据存放在哪里,也不需要知道由分布式系统中的哪台服务器来完成。
复制数据的透明管理
分布式数据的复制有助于提高性能,更易于协调不同而又冲突的用户需求。同时,当某台服务器出现故障时,此服务器上的数据在其他服务器上还有备份,提高了系统的可用性。
这种多副本的方式对用户来说是透明的,即用户不需要知道副本的存在,由系统统一管理、协调副本的调用。
事务的可靠性
分布式数据处理具有重复的构成,因此消除了单点故障的问题,即系统中一个或多个服务器发送故障不会使整个系统瘫痪,从而提高了系统的可靠性。
但是在分布式系统中,事务是并发的, 即不同用户可能在同一时间对同一数据源进行访问,这就要求系统支持分布式的并发控制,保证系统中数据的一致。
分布式系统可以解决海量数据的存储和访问,但是在分布式环境下,数据库会遇到更为复杂的问题,举例如下。
- 数据在分布式环境下以多副本方式进行存储,那么,在为用户提供数据访问时如何选择一个副本,或者用户修改了某一副本的数据,如何让系统中每个副本都得到更新。
- 如果正在更新系统所有副本信息时,某个服务器由于网络或硬、软件功能出现问题导致其发生故障。在这种情况下,如何确保故障恢复时,此服务器上的副本与其他副本一致。
这些问题给分布式数据库管理系统带来了挑战,它们是分布式系统固有的复杂性,但更重要的是对分布数据的管理,控制数据之间的一致性以及数据访问的安全性。
CAP理论是什么?
CAP 理论是针对分布式数据库而言的,它是指在一个分布式系统中,一致性(Consistency, C)、可用性(Availability, A)、分区容错性(Partition Tolerance, P)三者不可兼得。
一致性(C)
一致性是指“all nodes see the same data at the same time”,即更新操作成功后,所有节点在同一时间的数据完全一致。
一致性可以分为客户端和服务端两个不同的视角:
- 从客户端角度来看,一致性主要指多个用户并发访问时更新的数据如何被其他用户获取的问题;
- 从服务端来看,一致性则是用户进行数据更新时如何将数据复制到整个系统,以保证数据的一致。
一致性是在并发读写时才会出现的问题,因此在理解一致性的问题时,一定要注意结合考虑并发读写的场景。
可用性(A)
可用性是指“reads and writes always succeed”,即用户访问数据时,系统是否能在正常响应时间返回结果。
好的可用性主要是指系统能够很好地为用户服务,不出现用户操作失败或者访问超时等用户体验不好的情况。在通常情况下,可用性与分布式数据冗余、负载均衡等有着很大的关联。
分区容错性(P)
分区容错性是指“the system continues to operate despite arbitrary message loss or failure of part of the system”,即分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务。
分区容错性和扩展性紧密相关。在分布式应用中,可能因为一些分布式的原因导致系统无法正常运转。分区容错性高指在部分节点故障或出现丢包的情况下,集群系统仍然能提供服务,完成数据的访问。分区容错可视为在系统中采用多副本策略。
相互关系
CAP 理论认为分布式系统只能兼顾其中的两个特性,即出现 CA、CP、AP 三种情况,如图所示。
CA without P
如果不要求 Partition Tolerance,即不允许分区,则强一致性和可用性是可以保证的。其实分区是始终存在的问题,因此 CA 的分布式系统更多的是允许分区后各子系统依然保持 CA。
CP without A
如果不要求可用性,相当于每个请求都需要在各服务器之间强一致,而分区容错性会导致同步时间无限延长,如此 CP 也是可以保证的。很多传统的数据库分布式事务都属于这种模式。
AP without C
如果要可用性高并允许分区,则需放弃一致性。一旦分区发生,节点之间可能会失去联系,为了实现高可用,每个节点只能用本地数据提供服务,而这样会导致全局数据的不一致性。
总结
在实践中,可根据实际情况进行权衡,或者在软件层面提供配置方式,由用户决定如何选择 CAP 策略。
CAP 理论可用在不同的层面,可以根据 CAP 原理定制局部的设计策略,例如,在分布式系统中,每个节点自身的数据是能保证 CA 的,但在整体上又要兼顾 AP 或 CP。
ACID原则是什么?
ACID 是关系型数据库的事务机制需要遵守的原则。事务是一个一致和可靠计算的基本单元,由作为原子单元执行的一系列数据库操作组成。数据库库一般在启动时会提供事务机制,包括事务启动、停止、取消或回滚等。
关系型数据库支持事务的 ACID 原则,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability),这四种原则保证在事务过程当中数据的正确性,具体描述如下。
原子性(A)
一个事务的所有系列操作步骤被看成一个动作,所有的步骤要么全部完成,要么一个也不会完成。如果在事务过程中发生错误,则会回滚到事务开始前的状态,将要被改变的数据库记录不会被改变。
一致性(C)
一致性是指在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏,即数据库事务不能破坏关系数据的完整性及业务逻辑上的一致性。
隔离性(I)
主要用于实现并发控制,隔离能够确保并发执行的事务按顺序一个接一个地执行。通过隔离,一个未完成事务不会影响另外一个未完成事务。
持久性(D)
一旦一个事务被提交,它应该持久保存,不会因为与其他操作冲突而取消这个事务。
从事务的四个特性可以看到关系型数据库是要求强一致性的,但是这一点在 NoSQL 数据库中是重点弱化的机制。原因是当数据库保存强一致性时,很难保证系统具有横向扩展和可用性的优势,因此针对分布式数据存储管理只提供了弱一致性的保障,即 BASE 原理。
BASE原理与最终一致性
BASE 理论是针对 NoSQL 数据库而言的,它是对 CAP 理论中一致性(C)和可用性(A)进行权衡的结果,源于提出者自己在大规模分布式系统上实践的总结。其核心思想是无法做到强一致性,但每个应用都可以根据自身的特点,采用适当方式达到最终一致性。
基本可用(Basically Available)
基本可用指分布式系统在出现故障时,系统允许损失部分可用性,即保证核心功能或者当前最重要功能可用。
对于用户来说,他们当前最关注的功能或者最常用的功能的可用性将会获得保证,但是其他功能会被削弱。
软状态(Soft-state)
软状态允许系统数据存在中间状态,但不会影响系统的整体可用性,即允许不同节点的副本之间存在暂时的不一致情况。
最终一致性(Eventually Consistent)
最终一致性要求系统中数据副本最终能够一致,而不需要实时保证数据副本一致。例如,银行系统中的非实时转账操作,允许 24 小时内用户账户的状态在转账前后是不一致的,但 24 小时后账户数据必须正确。
最终一致性是 BASE 原理的核心,也是 NoSQL 数据库的主要特点,通过弱化一致性,提高系统的可伸缩性、可靠性和可用性。而且对于大多数 Web 应用,其实并不需要强一致性,因此牺牲一致性而换取高可用性,是多数分布式数据库产品的方向。
最终一致性可以分为客户端和服务端两个不同的视角。
从客户端的角度看
从客户端来看,一致性主要指的是多并发访问时更新过的数据如何获取的问题,最终一致性有以下 5 个变种。
一致性变种 | 说明 |
---|---|
因果一致性 | 如果进程 A 通知进程 B 它已更新了一个数据项,那么,进程 B 的后续访问将返回更新后的值,且一次写入将保证取代前一次写入。与进程 A 无因果关系的进程 C 的访问遵守一般的最终一致性规则。 |
读己之所写(Read-Your-Writes) 一致性 | 当进程 A 自己更新一个数据项之后,它总是访问到更新过的值,且不会看到旧值。这是因果一致性模型的一个特例。 |
会话(Session)—致性 | 这是上一个模型的实用版本,它把访问存储系统的进程放到会话的上下文中。只要会话还存在,系统就保证“读己之所写”一致性。如果由于某些失败情形令会话终止,就要建立新的会话,而且系统保证不会延续到新的会话。 |
单调(Monotonic)读一致性 | 如果进程已经看到过数据对象的某个值,那么任何后续访问都不会返回在那个值之前的值。 |
单调写一致性 | 系统保证来自同一个进程的写操作顺序执行。 |
上述最终一致性的不同方式可以进行组合,例如,单调读一致性和“读己之所写”一致性就可以组合实现。从实践的角度来看,这两者的组合读取自己更新的数据,一旦读取到最新的版本,就不会再读取旧版本,对基于此架构上的程序开发来说,会减少很多额外的烦恼。
从服务器的角度看
从服务端来看,如何尽快地将更新后的数据分布到整个系统,降低达到最终一致性的时间窗口,是提高系统的可用度和用户体验度非常重要的方面。
分布式数据系统有以下特性:
- N 为数据复制的份数。
- W 为更新数据时需要进行写操作的节点数。
- R 为读取数据的时候需要读取的节点数。
如果 W+R>N,写的节点和读的节点重叠,则是强一致性。例如,对于典型的一主一备同步复制的关系型数据库(N=2, W=2,R=1),则不管读的是主库还是备库的数据,都是一致的。
如果 W+R≤N,则是弱一致性。例如,对于一主一备异步复制的关系型数据库(N=2,W=1,R=1),如果读的是备库,则可能无法读取主库已经更新过的数据,所以是弱一致性。
对于分布式系统,为了保证高可用性,一般设置 N≥3。设置不同的N、W、R 组合,是在可用性和一致性之间取一个平衡,以适应不同的应用场景。
如果N=W 且 R=1,则任何一个写节点失效,都会导致写失败,因此可用性会降低。但是由于数据分布的 N 个节点是同步写入的,因此可以保证强一致性。
如果 N=R 且 W=1,则只需要一个节点写入成功即可,写性能和可用性都比较高。但是读取其他节点的进程可能不能获取更新后的数据,因此是弱一致性。在这种情况下,如果 W<(N+1)/2,并且写入的节点不重叠,则会存在写冲突。
NoSQL数据库有哪些?
关系型数据库产品很多,如 MySQL、Oracle、Microsoft SQL Sever 等,但它们的基本模型都是关系型数据模型。NoSQL 并没有统一的模型,而且是非关系型的。
常见的 NoSQL 数据库包括键值数据库、列族数据库、文档数据库和图形数据库,其具体分类和特点如表所示。
分类 | 相关产品 | 应用场景 | 数据模型 | 优点 | 缺点 |
---|---|---|---|---|---|
键值数据库 | Redis、Memcached、Riak | 内容缓存,如会话、配置文件、参数等; 频繁读写、拥有简单数据模型的应用 | <key,value> 键值对,通过散列表来实现 | 扩展性好,灵活性好,大量操作时性能高 | 数据无结构化,通常只被当做字符串或者二进制数据,只能通过键来查询值 |
列族数据库 | Bigtable、HBase、Cassandra | 分布式数据存储与管理 | 以列族式存储,将同一列数据存在一起 | 可扩展性强,查找速度快,复杂性低 | 功能局限,不支持事务的强一致性 |
文档数据库 | MongoDB、CouchDB | Web 应用,存储面向文档或类似半结构化的数据 | <key,value> value 是 JSON 结构的文档 | 数据结构灵活,可以根据 value 构建索引 | 缺乏统一查询语法 |
图形数据库 | Neo4j、InfoGrid | 社交网络、推荐系统,专注构建关系图谱 | 图结构 | 支持复杂的图形算法 | 复杂性高,只能支持一定的数据规模 |
NoSQL 数据库并没有一个统一的架构,两种不同的 NoSQL 数据库之间的差异程度,远远超过两种关系型数据库之间的不同。
可以说,NoSQL 数据库各有所长,一个优秀的 NoSQL 数据库必然特别适用于某些场合或者某些应用,在这些场合中会远远胜过关系型数据库和其他的 NoSQL 数据库。
常见的 NoSQL 数据库分为以下几种。
1) 键值数据库
这一类数据库主要会使用到一个散列表,这个表中有一个特定的键和一个指针指向特定的数据。
键值模型对于 IT 系统来说,其优势在于简单、易部署。键值数据库可以按照键对数据进行定位,还可以通过对键进行排序和分区,以实现更快速的数据定位。
2) 列族数据库
列族数据库通常用来应对分布式存储的海量数据。键仍然存在,但是它们的特点是指向了多个列,如图所示。
此列族数据库表中由两行组成,每一行都有关键字 Row Key,每一行由多个列族组成,即 Column-Family-1 和 Column-Family-2,而每个列族由多个列组成。
3) 文档数据库
文档数据库的灵感来自 Lotus Notes 办公软件,它与键值数据库类似。该类型的数据模型是版本化的文档,文档以特定的格式存储,如 JSON。
文档数据库可以看作键值数据库的升级版,允许之间嵌套键值,如图所示。
文档数据库比键值数据库的查询效率更高, 因为文档数据库不仅可以根据键创建索引,同时还可以根据文档内容创建索引。
4) 图形数据库
图形数据库来源于图论中的拓扑学,以节点、边及节点之间的关系来存储复杂网络中的数据,如图所示。
这种拓扑结构类似 E-R 图,但在图形模式中,关系和节点本身就是数据,而在 E-R 图中,关系描述的是一种结构。
内存数据库是什么?
内存数据库主要是把磁盘的数据加载到内存中进行相应操作。
与直接读取磁盘数据相比,内存的数据读取速度要高出几个数量级,因此,将数据保存在内存中能够极大地提高应用的性能。
内存数据库改变了磁盘数据管理的传统方式,基于全部数据都在内存中的特点重新设计了体系结构,并且在数据缓存、快速算法、并行操作方面也进行了相应的升级,因此,其数据处理速度一般比传统数据库的数据处理速度快几十倍。
内存数据库的最大特点是其应用数据常驻内存中,即活动事务只与实时内存数据库的内存进行数据交流。
常见的内存数据库有 Memcached、Redis、SQLite、Microsoft SQL Server Compact 等。
Memcached入门教程
Memcached 是 LiveJournal 旗下 Danga Interactive 公司的布拉德•菲茨帕特里克(BradFitzpatric)开发的一款内存数据库,现在已被应用于 Facebook、LiveJournal 等公司用于提高 Web 服务质量。
目前这款软件流行于全球各地,经常被用来建立缓存项目,并以此分担来自传统数据库的并发负载压力。
Memcached 可以轻松应对大量同时出现的数据请求,而且它拥有独特的网络结构,在工作机制方面,它还可以在内存中单独开辟新的空间,建立 HashTable,并对 HashTable 进行有效的管理。
我们有时会见到 Memcache 和 Memcached 两种不同的说法,为什么会有两种名称?
其实 Memcache 是这个项目的名称,而 Memcached 是它服务器端的主程序文件名。一个是项目名称,另一个是主程序文件名。
为什么要使用 Memcached
由于网站的高并发读写和对海量数据的处理需求,传统的关系型数据库开始出现瓶颈。
对数据库的高并发读写
关系型数据库本身就是个庞然大物,处理过程非常耗时(如解析 SQL 语句、事务处理等)。如果对关系型数据库进行高并发读写(每秒上万次的访问),数据库系统是无法承受的。
对海量数据的处理
对于大型的 SNS 网站(如 Twitter、新浪微博),每天有上千万条的数据产生。对关系型数据库而言,如果在一个有上亿条数据的数据表中查找某条记录,效率将非常低。
使用 Memcached 就能很好地解决以上问题。
多数 Web 应用都将数据保存到关系型数据库中(如 MySQL ),Web 服务器从中读取数据并在浏览器中显示。但随着数据量的增大,访问的集中,关系型数据库的负担就会加重,岀现响应缓慢、网站打开延迟时间长等问题。
因此,使用 Memcached 的主要目的是通过自身内存中缓存关系型数据库的查询结果,减少数据库自身被访问的次数,以提高动态 Web 应用的速度,增强网站架构的并发能力和可扩展性。
通过在事先规划好的系统内存空间中临时缓存数据库中的各类数据,以达到减少前端业务服务对关系型数据库的直接高并发访问,从而达到提升大规模网站集群中动态服务的并发访问能力。
Web 服务器读取数据时先读 Memcached 服务器,若 Memcached 没有所需的数据,则向数据库请求数据,然后 Web 再把请求到的数据发送到 Memcached,如下图所示。
Redis是什么?
Redis 是一个开源的、高性能的、键值对内存数据库。它通过提供多种键值数据类型来满足不同场景下的存储需求,并借助许多高层级的接口使其可以胜任如缓存、队列系统等不同的角色。
本小节将介绍 Redis 的历史和特性,以使读者能够快速地对 Redis 有一个全面的了解。
Redis 历史与发展
2008 年,意大利的一家创业公司 Merzia 推出了一款基于 MySQL 的网站实时统计系统 —— LLOOGG,然而没过多久,该公司的创始人萨尔瓦托•桑菲利普(Salvatore Sanfilippo)便对这个系统的性能感到失望,于是他决定亲自为 LLOOGG 量身定做一个数据库,并于 2009 年开发完成, 这个数据库就是Redis。
不过萨尔瓦托并不满足只将 Redis 用于 LLOOGG 这一款产品,而是希望让更多的人使用它,于是萨尔瓦托将 Redis 开源发布,并开始和 Redis 的另一名主要的代码贡献者皮特•诺德胡斯(Pieter Noordhuis)一起继续着 Redis 的开发,直到今天。
萨尔瓦托自己也没有想到,在短短的几年时间内,Redis 就拥有了庞大的用户群体。Hacked News 在 2012 年发布了一份数据库的使用情况调查,结果显示有近 12% 的公司在使用 Redis。
国内如新浪微博和知乎,国外如 GitHub、Stack Overflow、Flickr、暴雪和 Instagram,都是 Redis 的用户。现在使用 Redis 的用户越来越多,大多数的互联网公司都使用 Redis 作为公共缓存。
VMware 公司从 2010 年开始赞助 Redis 的开发,萨尔瓦托和皮特也分别于同年的 3 月和 5 月加入 VMware,全职开发 Redis。
Redis 特性
存储结构
有过脚本语言编程经验的读者对字典(或称映射、关联数组)数据结构一定很熟悉,如在代码 dict[“key”]=“value” 中,“diet”是一个字典结构变量,字符串“key”是键名,而“value”是键值,在字典中可以获取或设置键名对应的键值,也可以删除一个键。
Redis 是 Remote Dictionary Server(远程字典服务器)的缩写,它以字典结构存储数据,并允许其他应用通过 TCP 读写字典中的内容。同大多数脚本语言中的字典一样,Redis 字典中的键值除了可以是字符串,还可以是其他数据类型。
到目前为止,Redis 支持的键值数据类型有:字符串类型、散列类型、列表类型、集合类型和有序集合类型。
这种字典形式的存储结构与常见的 MySQL 等关系数据库的二维表形式的存储结构有很大的差异。举个例子,在程序中使用 post 变量存储了一篇文章的数据(包括标题、正文、阅读量和标签),如下所示:
post[“title”] = “Hello World!”
post[“content”] = “Blablabla…”
post[“views”] = 0
post[“tags”] = [“PHP”,“Ruby”,“Node.js”]
现在希望将这篇文章的数据存储在数据库中,并且要求可以通过标签检索岀文章。
如果使用关系数据库存储,一般会将其中的标题、正文和阅读量存储在一个表中,而将标签存储在另一个表中,然后使用第三个表连接文章和标签表。需要查询时还需要连接三个表,不是很直观。
而 Redis 字典结构的存储方式和对多种键值数据类型的支持使得开发者可以将程序中的数据直接映射到 Redis 中,数据在 Redis 中的存储形式和其在程序中的存储方式非常相似。
使用 Redis 的另一个优势是其对不同的数据类型提供了非常方便的操作方式,如使用集合类型存储文章标签,Redis 可以对标签进行如交集、并集等集合运算操作。
内存存储与持久化
Redis 数据库中的所有数据都存储在内存中。由于内存的读写速度远高于硬盘,因此 Redis 在性能上与其他基于硬盘存储的数据库相比有非常明显的优势。在一台普通的笔记本电脑上,Redis 可以在一秒内读写超过 10 万个键值。
将数据存储在内存中也有问题,例如,程序退出后内存中的数据会丢失。不过 Redis 提供了对持久化的支持,即可以将内存中的数据异步写入硬盘中,同时不影响其继续提供服务。
功能丰富
Redis 虽然是作为数据库开发的,但由于其提供了丰富的功能,越来越多的人将其用作缓存、 队列系统等。Redis 可谓是名副其实的多面手。
Redis 可以为每个键设置生存时间(Time To Live, TTL),生存时间到期后键会自动被删除。 这一功能配合出色的性能让 Redis 可以作为缓存系统来使用,而且由于 Redis 支持持久化和丰富的数据类型,使其成为另一个非常流行的缓存系统 Memcached 的有力竞争者。
讨论 Redis 和 Memcached 的优劣一直是一个热门的话题。由于 Redis 是单线程模型,而 Memcached 支持多线程,所以在多核服务器上后者的性能更高一些。
然而,前面已经介绍过,Redis 的性能已经足够优异,在绝大部分场合下其性能都不会成为瓶颈。所以在使用时更应该关心的是二者在功能上的区别,如果需要用到高级的数据类型或持久化等功能,Redis 将会是 Memcached 很好的替代品。
作为缓存系统,Redis 还可以限定数据占用的最大内存空间,在数据达到空间限制后可以按照一定的规则自动淘汰不需要的键。
除此之外,Redis 的列表类型键可以用来实现队列,支持阻塞式读取,并且可以很容易地实现一个高性能的优先级队列。同时,在更高层面上,Redis 还支持“发布/订阅”的消息模式,用户可以基于此构建聊天室等系统。
简单稳定
如果一个工具使用起来太复杂,即使它的功能再丰富也很难吸引人。Redis 直观的存储结构使其通过程序与 Redis 交互十分简单。在 Redis 中使用命令来读写数据,命令语句之于 Redis 就相当于 SQL 之于关系数据库。
例如,在关系数据库中要获取 posts 表内 id 为 1 的记录的 title 字段的值,可以使用如下 SQL 语句实现:
SELECT title FROM posts WHERE id=1 LIMIT 1
相对应的,在 Redis 中要读取键名为 post:1 的散列类型键的 title 字段的值,可以使用如下命令语句实现:
HGET post : 1 title
其中,HGET 就是一个命令。Redis 提供了 100 多个命令,但是常用的只有十几个,并且每个命令都很容易记住。
Redis 提供了几十种不同编程语言的客户端库,这些库都封装了 Redis 的命令,这样在程序中与 Redis 进行交互变得很容易。
有些库还提供了可以将编程语言中的数据类型直接以相应的形式存储到 Redis 中(如将数组直接以列表类型存入 Redis)的简单方法,使用起来非常方便。
Redis 使用 C 语言开发,代码量只有 3 万多行。这降低了用户通过修改 Redis 源代码来使之更适合自己项目需要的门槛。对于希望“榨干”数据库性能的开发者而言,这无疑具有很大的吸引力。
Redis 是开源的,有将近 100 名开发者为 Redis 贡献了代码。良好的开发氛围和严谨的版本发布机制使得 Redis 的稳定版本的性能非常可靠,如此多的公司选择使用 Redis 也可以印证这 一点。
Memcached 与 Redis 比较
Memcached 与 Redis 的比较见下表。
数据库 | CPU | 内存利用率 | 持久性 | 数据结构 | 工作环境 |
---|---|---|---|---|---|
Memcached | 支持多核 | 高 | 无 | 简单 | Linux/Windows |
Redis | 单核 | 低(压缩比 Memcached 高) | 有(硬盘存储,主从同步) | 复杂 | Linux |
四、分布式系统
什么是分布式系统
分布式系统是由一组通过网络进行通信、为了完成共同的任务而协调工作的计算机节点组成的系统。分布式系统的出现是为了用廉价的、普通的机器完成单个计算机无法完成的计算、存储任务。其目的是利用更多的机器,处理更多的数据。
首先需要明确的是,只有当单个节点的处理能力无法满足日益增长的计算、存储任务的时候,且硬件的提升(加内存、加磁盘、使用更好的CPU)高昂到得不偿失的时候,应用程序也不能进一步优化的时候,我们才需要考虑分布式系统。因为,分布式系统要解决的问题本身就是和单机系统一样的,而由于分布式系统多节点、通过网络通信的拓扑结构,会引入很多单机系统没有的问题,为了解决这些问题又会引入更多的机制、协议,带来更多的问题。。。
在很多文章中,主要讲分布式系统分为分布式计算(computation)与分布式存储(storage)。计算与存储是相辅相成的,计算需要数据,要么来自实时数据(流数据),要么来自存储的数据;而计算的结果也是需要存储的。在操作系统中,对计算与存储有非常详尽的讨论,分布式系统只不过将这些理论推广到多个节点罢了。
那么分布式系统怎么将任务分发到这些计算机节点呢,很简单的思想,分而治之,即分片(partition)。对于计算,那么就是对计算任务进行切换,每个节点算一些,最终汇总就行了,这就是MapReduce的思想;对于存储,更好理解一下,每个节点存一部分数据就行了。当数据规模变大的时候,Partition是唯一的选择,同时也会带来一些好处:
(1)提升性能和并发,操作被分发到不同的分片,相互独立
(2)提升系统的可用性,即使部分分片不能用,其他分片不会受到影响
理想的情况下,有分片就行了,但事实的情况却不大理想。原因在于,分布式系统中有大量的节点,且通过网络通信。单个节点的故障(进程crash、断电、磁盘损坏)是个小概率事件,但整个系统的故障率会随节点的增加而指数级增加,网络通信也可能出现断网、高延迟的情况。在这种一定会出现的“异常”情况下,分布式系统还是需要继续稳定的对外提供服务,即需要较强的容错性。最简单的办法,就是冗余或者复制集(Replication),即多个节点负责同一个任务,最为常见的就是分布式存储中,多个节点复杂存储同一份数据,以此增强可用性与可靠性。同时,Replication也会带来性能的提升,比如数据的locality可以减少用户的等待时间。
下面这种来自Distributed systems for fun and profit 的图形象生动说明了Partition与Replication是如何协作的。
Partition和Replication是解决分布式系统问题的一记组合拳,很多具体的问题都可以用这个思路去解决。但这并不是银弹,往往是为了解决一个问题,会引入更多的问题,比如为了可用性与可靠性保证,引用了冗余(复制集)。有了冗余,各个副本间的一致性问题就变得很头疼,一致性在系统的角度和用户的角度又有不同的等级划分。如果要保证强一致性,那么会影响可用性与性能,在一些应用(比如电商、搜索)是难以接受的。如果是最终一致性,那么就需要处理数据冲突的情况。CAP、FLP这些理论告诉我们,在分布式系统中,没有最佳的选择,都是需要权衡,做出最合适的选择。
分布式系统挑战
分布式系统需要大量机器协作,面临诸多的挑战:
第一,异构的机器与网络:
分布式系统中的机器,配置不一样,其上运行的服务也可能由不同的语言、架构实现,因此处理能力也不一样;节点间通过网络连接,而不同网络运营商提供的网络的带宽、延时、丢包率又不一样。怎么保证大家齐头并进,共同完成目标,这四个不小的挑战。
第二,普遍的节点故障:
虽然单个节点的故障概率较低,但节点数目达到一定规模,出故障的概率就变高了。分布式系统需要保证故障发生的时候,系统仍然是可用的,这就需要监控节点的状态,在节点故障的情况下将该节点负责的计算、存储任务转移到其他节点
第三,不可靠的网络:
节点间通过网络通信,而网络是不可靠的。可能的网络问题包括:网络分割、延时、丢包、乱序。
相比单机过程调用,网络通信最让人头疼的是超时:节点A向节点B发出请求,在约定的时间内没有收到节点B的响应,那么B是否处理了请求,这个是不确定的,这个不确定会带来诸多问题,最简单的,是否要重试请求,节点B会不会多次处理同一个请求。
总而言之,分布式的挑战来自不确定性,不确定计算机什么时候crash、断电,不确定磁盘什么时候损坏,不确定每次网络通信要延迟多久,也不确定通信对端是否处理了发送的消息。而分布式的规模放大了这个不确定性,不确定性是令人讨厌的,所以有诸多的分布式理论、协议来保证在这种不确定性的情况下,系统还能继续正常工作。
而且,很多在实际系统中出现的问题,来源于设计时的盲目乐观,觉得这个、那个应该不会出问题。Fallacies_of_distributed_computing很有意思,介绍了分布式系统新手可能的错误的假设:
The network is reliable.
Latency is zero.
Bandwidth is infinite.
The network is secure.
Topology doesn’t change.
There is one administrator.
Transport cost is zero.
The network is homogeneous.
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
不确定会带来诸多问题,最简单的,是否要重试请求,节点B会不会多次处理同一个请求。
总而言之,分布式的挑战来自不确定性,不确定计算机什么时候crash、断电,不确定磁盘什么时候损坏,不确定每次网络通信要延迟多久,也不确定通信对端是否处理了发送的消息。而分布式的规模放大了这个不确定性,不确定性是令人讨厌的,所以有诸多的分布式理论、协议来保证在这种不确定性的情况下,系统还能继续正常工作。
而且,很多在实际系统中出现的问题,来源于设计时的盲目乐观,觉得这个、那个应该不会出问题。Fallacies_of_distributed_computing很有意思,介绍了分布式系统新手可能的错误的假设:
The network is reliable.
Latency is zero.
Bandwidth is infinite.
The network is secure.
Topology doesn’t change.
There is one administrator.
Transport cost is zero.
The network is homogeneous.
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
[外链图片转存中…(img-HP6HGfee-1713173825710)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!