学习分享(第3期):你所理解的架构是什么?

学习分享(第3期):你所理解的架构是什么?

本文摘要:浅谈应用架构、业务架构、技术架构。

什么是架构?

说到架构,这个概念没有很清晰的范围划分,也没有一个标准的定义,每个人的理解可能都不一样。

架构在百度百科中是这样定义的:架构,又名软件架构,是有关软件整体结构与组件的抽象描述,用于指导大型软件系统各个方面的设计。

我们可以理解为:架构设计的主要目的是为了解决软件系统复杂度带来的问题。

卡内基·梅隆大学的玛丽·肖(Mary Shaw)和戴维·加兰(David Garlan)在文章《软件架构介绍》(An Introduction to Software Architecture)中写到:

“When systems are constructed from many components, the organization of the overall system-the software architecture-presents a new set of design problems.”

译:随着软件系统规模的增加,计算相关的算法和数据结构不再构成主要的设计问题;当系统由许多部分组成时,整个系统的组织,也就是所说的“软件架构”,导致了一系列新的设计问题。

软件架构的核心价值,即是控制系统的复杂性,将核心业务逻辑和技术细节的分离与解耦。

架构师的职责是努力训练自己的思维,用它去理解复杂的系统,通过合理的分解和抽象,理解并解析需求,创建有用的模型,确认、细化并扩展模型,管理架构;能够进行系统分解形成整体架构,能够正确的技术选型,能够制定技术规格说明并有效推动实施落地。

阅读更多
学习分享(第 2 期):从源码层面看 Redis 节省内存的设计

学习分享(第 2 期):从源码层面看 Redis 节省内存的设计

这里记录的是学习分享的内容,文章维护在 Github:studeyang/leanrning-share

回顾

在文章《Redis 的 String 类型,原来这么占内存》中,我们学习了 SDS 的底层结构,发现 SDS 存储了很多的元数据,再加上全局哈希表的实现,使得 Redis String 类型在内存占用方面并不理想。

然后在文章《学习分享(第1期)之Redis:巧用Hash类型节省内存》中,我们学习了另一种节省内存的方案,使用 ziplist 结构的 Hash 类型,内存占用减少了一半,效果显著。

虽然我们在使用 String 类型后,占用了较多内存,但其实 Redis 是对 SDS 做了节省内存设计的。除此之外,Redis 在其他方面也都考虑了内存开销,今天我们就从源码层面来看看都做了哪些节省内存的设计。

文中代码版本为 6.2.4。

一、redisObject 的位域定义法

我们知道,redisObject 是底层数据结构如 SDS, ziplist 的封装,因此,redisObject 如果能做优化,最终也能带来节省内存的用户体验。在源码 server.h 中定义了 redisObject 的结构体,如下面代码所示:

1
2
3
4
5
6
7
8
9
#define LRU_BITS 24

typedef struct redisObject {
unsigned type:4;//对象类型(4位=0.5字节)
unsigned encoding:4;//编码(4位=0.5字节)
unsigned lru:LRU_BITS;//记录对象最后一次被应用程序访问的时间(24位=3字节)
int refcount;//引用计数。等于0时表示可以被垃圾回收(32位=4字节)
void *ptr;//指向底层实际的数据存储结构,如:sds等(8字节)
} robj;

type, encoding, lru, refcount 都是 redisObject 的元数据,redisObject 的结构如下图所示。

阅读更多

学习分享(第 1 期)之 Redis:巧用 Hash 类型节省内存

开篇

之前的分享内容都是相对零散的知识点,不成体系。以后的每周分享,我会尽量将每篇文章串连起来,于是我决定做一个专栏,名字就叫《学习分享》。这是该系列的第一篇。

《学习分享》内容大多来自我平时学习过程中的笔记,笔记仓库在 Github:studeyang/technotes。其中我认为有深度、对工作有帮助的内容,就会以文章的形式发表在该专栏,内容会首发在我的公众号掘金今日头条,也会维护在 Github:studeyang/leanrning-share

回顾

上篇文章《Redis 的 String 类型,原来这么占内存》中,我们使用 String 类型存储了图片 ID 和图片存储对象 ID,结果发现两个 Long 类型的 ID 竟然占了 68 字节内存。具体验证过程,我还是贴一下方便你回顾。

1、查看 Redis 的初始内存使用情况。

1
2
3
127.0.0.1:6379> info memory
# Memory
used_memory:871840

2、接着插入 10 条数据。

1
2
3
4
5
6
7
8
9
10
10.118.32.170:0> set 1101000060 3302000080
10.118.32.170:0> set 1101000061 3302000081
10.118.32.170:0> set 1101000062 3302000082
10.118.32.170:0> set 1101000063 3302000083
10.118.32.170:0> set 1101000064 3302000084
10.118.32.170:0> set 1101000065 3302000085
10.118.32.170:0> set 1101000066 3302000086
10.118.32.170:0> set 1101000067 3302000087
10.118.32.170:0> set 1101000068 3302000088
10.118.32.170:0> set 1101000069 3302000089

3、再次查看内存。

1
2
3
127.0.0.1:6379> info memory
# Memory
used_memory:872528

可以看到,存储 10 个图片,内存使用了 688 个字节。一个图片 ID 和图片存储对象 ID 的记录平均用了 68 字节。

这是上次我们讲述的场景。

并且还留下了一道思考题:既然 String 类型这么占内存,那么你有好的方案来节省内存吗?

今天呢,我们就来具体谈一谈。

阅读更多

架构师应具备什么能力?

要回答这个问题,我们首先要搞清楚,为什么要做架构设计?不做行不行?

1、架构设计的目的

早在 1960 年代,诸如艾兹格·迪杰斯特拉就已经涉及软件架构这个概念了。自1990年代以来,软件架构这个概念开始越来越流行起来。

卡内基·梅隆大学的玛丽·肖(Mary Shaw)和戴维·加兰(David Garlan)对软件架构做了很多研究,他们在 1994 年的一篇文章《软件架构介绍》(An Introduction to Software Architecture)中写到:

“When systems are constructed from many components, the organization of the overall system-the software architecture-presents a new set of design problems.”

译:随着软件系统规模的增加,计算相关的算法和数据结构不再构成主要的设计问题;当系统由许多部分组成时,整个系统的组织,也就是所说的“软件架构”,导致了一系列新的设计问题。

这一系列新的问题诸如:

  • 系统规模庞大,内部耦合严重,开发效率低;
  • 系统耦合严重,牵一发动全身,后续修改和扩展困难;
  • 系统逻辑复杂,容易出问题,出问题后很难排查和修复。

可以看到,软件技术其实就是与“复杂度”作斗争的,架构的出现也不例外。简而言之,架构也是为了应对软件系统复杂度而提出的一个解决方案,通过回顾架构产生的历史背景和原因,我们可以基本推导出答案:架构设计的主要目的是为了解决软件系统复杂度带来的问题。

《第50次中国互联网络发展状况统计报告》显示,截至 2022 年 6 月,我国网民规模数达 10.51 亿。架构复杂度越来越高,已成必然。

架构复杂度主要体现在以下方面。

阅读更多

Redis String类型的内存开销都花在哪儿了?

1、场景介绍

假设现在我们要开发一个图片存储系统,要求这个系统能够根据图片 ID 快速查找到图片存储对象 ID。图片 ID 和图片存储对象 ID 的样例数据如下:

1
2
photo_id: 1101000060
photo_obj_id: 3302000080

在这种场景下,图片 ID 和图片存储对象 ID 刚好是一对一的关系,是典型的“键 - 单值”模式,Redis 的 String 类型提供了“一个键对应一个值的数据”的保存形式,在这种场景下刚好适用。

确定使用 String 类型后,接下来我们通过实战,来看看它的内存使用情况。首先通过下面命令连接上 Redis。

本文我使用的 Redis Server 及下文源码都是 6.2.4 版本。

1
redis-cli -h 127.0.0.1 -p 6379

然后执行下面的命令查看 Redis 的初始内存使用情况。

1
2
3
127.0.0.1:6379> info memory
# Memory
used_memory:871840

接着插入 10 条数据:

1
2
3
4
5
6
7
8
9
10
10.118.32.170:0> set 1101000060 3302000080
10.118.32.170:0> set 1101000061 3302000081
10.118.32.170:0> set 1101000062 3302000082
10.118.32.170:0> set 1101000063 3302000083
10.118.32.170:0> set 1101000064 3302000084
10.118.32.170:0> set 1101000065 3302000085
10.118.32.170:0> set 1101000066 3302000086
10.118.32.170:0> set 1101000067 3302000087
10.118.32.170:0> set 1101000068 3302000088
10.118.32.170:0> set 1101000069 3302000089

再次查看内存:

1
2
3
127.0.0.1:6379> info memory
# Memory
used_memory:872528

可以看到,存储 10 个图片,内存使用了 688 个字节。一个图片 ID 和图片存储对象 ID 的记录平均用了 68 字节。

但问题是,一组图片 ID 及其存储对象 ID 的记录,实际只需要 16 字节就可以了。图片 ID 和图片存储对象 ID 都是 10 位数,而 8 字节的 Long 类型最大可以表示 2 的 64 次方的数值,肯定可以表示 10 位数。这样算下来只需 16 字节就可以了,为什么 String 类型却用了 68 字节呢?

阅读更多
Redis高可用之 Sentinel 机制实现细节
(byte)1658385462vv16=-40,怎么算的?
Git如何删除指定commit?如何修改历史提交人信息?
XXL-JOB核心源码导读及时间轮原理剖析

XXL-JOB核心源码导读及时间轮原理剖析

你好,今天我想和你分享一下XXL-JOB的核心实现。如果你是XXL-JOB的用户,那么你肯定思考过它的实现原理;如果你还未接触过这个产品,那么可以通过本文了解一下。

阅读更多
Redis高可用全景一览

Redis高可用全景一览

对于一项技术的学习,我们要对这项技术有一个全局观,下面是一张 Redis 全景图,画得非常全面。

阅读更多