数据库类型总结
关系型数据库和非关系型数据库各自有其适用的场景和优势。关系型数据库适合处理结构化数据,支持复杂查询和事务,但在大规模数据和高并发场景下可能表现较差。非关系型数据库适用于半结构化和非结构化数据,具有高扩展性和灵活性,但需要在设计时权衡一致性和数据模型的选择。选择合适的数据库取决于具体的业务需求和技术场景,需要综合考虑数据结构、查询需求、性能、可扩展性等因素。
关系型数据库(RDBMS):
关系型数据库采用表格形式来存储数据,每个表都由多个字段组成,数据以行的形式存储。常见的关系型数据库包括 MySQL、Oracle、SQL Server 等。
特点与优点:
- 结构化数据: 适用于处理结构化数据,如表格、行、列等。
- 强大的查询语言: 支持 SQL(Structured Query Language),能够进行复杂的查询和数据分析。
- 事务支持: 提供 ACID(原子性、一致性、隔离性、持久性)特性,保证数据的一致性和完整性。
- 数据完整性: 支持定义数据约束,如主键、外键、唯一性约束等,保障数据的完整性。
缺点和限制:
- 固定模式: 表格结构需要提前定义,难以适应数据模型的变化。
- 扩展性挑战: 在大规模、高并发场景下,扩展性相对较差。
- 存储冗余: 数据冗余较高,可能导致存储浪费。
非关系型数据库(NoSQL):
非关系型数据库不使用传统的表格结构,而是使用不同的数据模型来存储数据,如键值对、文档、列族、图形等。常见的非关系型数据库包括 MongoDB、Redis、Cassandra 等。
特点与优点:
- 灵活的数据模型: 适用于非结构化和半结构化数据,能够适应不同的数据需求。
- 高可扩展性: 采用分布式架构,具有良好的横向扩展能力,适用于大规模数据。
- 高性能: 非关系型数据库通常具有较低的读写延迟,适合高速读写场景。
- 适应变化: 可以在不破坏现有数据的情况下进行数据模型的变更。
缺点和限制:
- 缺乏标准化: 不同的非关系型数据库采用不同的数据模型和查询语言,缺乏统一的标准。
- 较少的事务支持: 与关系型数据库相比,部分非关系型数据库的事务支持较弱。
- 数据一致性挑战: 在分布式环境下,确保数据的一致性可能较为复杂。
为什么要有分布式数据库
分布式数据库是一种将数据分散存储在多个物理或逻辑节点上的数据库系统。结合老师的课件从容量、弹性和性价比三个角度来总结分布式数据库的特点:
容量(Capacity):
分布式数据库在容量方面具有显著优势:
- 横向扩展: 分布式数据库可以通过添加更多的节点来扩展容量,而不需要单独扩充单个节点的资源。这种横向扩展能够满足日益增长的数据存储需求。
- 分片技术: 数据可以被划分成多个分片(shard),每个分片可以存储在不同的节点上。这样的分片方式使得数据库可以处理大量的数据,而不受单个节点的限制。
弹性(Scalability):
分布式数据库在弹性方面具有以下特点:
- 自动负载均衡: 数据库系统能够自动将数据均匀分布到不同节点上,以实现负载均衡。这确保了每个节点的工作负荷相对均匀,提高了系统的整体性能。
- 可扩展性: 在需要增加容量或处理能力时,可以通过添加更多的节点来实现扩展,而不会对整体架构造成严重的影响。
- 弹性伸缩: 当负载减少时,可以根据需要动态减少节点数量,从而实现资源的弹性释放。
性价比(Cost-effectiveness):
分布式数据库在性价比方面有以下优势:
- 资源利用率: 分布式数据库可以合理分配资源,最大程度地利用硬件资源,从而提高性能。这使得分布式数据库在资源利用效率上具有较高的性价比。
- 廉价硬件: 分布式数据库通常可以在普通的、廉价的硬件上运行,而不需要高昂的硬件投入。这降低了系统的成本。
- 按需付费: 云计算服务提供商通常提供分布式数据库解决方案,可以按照使用量来付费。这种按需付费模式可以降低初始成本,提高了性价比。
综上所述,分布式数据库在容量、弹性和性价比等方面的特点使其成为处理大量数据和高并发请求的理想选择。然而,分布式系统也需要考虑一些复杂性,如数据一致性、故障处理等。在选择分布式数据库时,需要根据实际需求和场景来权衡这些特点和挑战。
课后作业
1:设计存储服务器
- 数据结构: 在存储服务器中,需要一个数据结构来存储键值对。这里我们可以选择一个
map来存储。 - RPC 接口: 定义存储服务器的 RPC 接口,包括
Put和Get操作。 - Put 操作: 在
Put操作中,存储服务器将接收到的键值对存储到数据结构中。 - Get 操作: 在
Get操作中,存储服务器根据给定的键返回相应的值。
2:实现存储服务器
- 实现 KeyValueServer 结构体: 用于存储数据和实现 RPC 接口。
- 实现 Put 方法: 将接收到的键值对存储到
Data数据结构中。 - 实现 Get 方法: 根据给定的键从
Data数据结构中检索相应的值。 - 启动存储服务器监听端口: 在主函数中监听指定的端口,等待客户端连接。
// storage_server.go
package main
// KeyValueServer 定义存储节点的 RPC 服务
type KeyValueServer struct {
Data map[string]string
}
// Put 存储键值对
func (s *KeyValueServer) Put(args KeyValueArgs, reply *bool) error {
s.Data[args.Key] = args.Value
*reply = true
return nil
}
// Get 获取键对应的值
func (s *KeyValueServer) Get(args KeyValueArgs, reply *string) error {
val, exists := s.Data[args.Key]
if exists {
*reply = val
} else {
*reply = ""
}
return nil
}
// KeyValueArgs 存储键值对的参数结构
type KeyValueArgs struct {
Key string
Value string
}
func main() {
server := new(KeyValueServer)
server.Data = make(map[string]string)
rpc.Register(server)
l, err := net.Listen("tcp", ":1234")
if err != nil {
fmt.Println("Error:", err)
os.Exit(1)
}
for {
conn, _ := l.Accept()
go rpc.ServeConn(conn)
}
}
3:设计客户端
- RPC 客户端: 使用 Go 的
net/rpc包创建客户端,用于与存储服务器进行通信。 - 远程调用 Put 方法: 构造键值对参数,使用客户端调用存储服务器的
Put方法,将键值对存储到服务器。 - 远程调用 Get 方法: 构造键参数,使用客户端调用存储服务器的
Get方法,获取键对应的值。