十种常用的架构模式

十种常用的架构模式

  1. 分层架构
    最常用的架构模式,一般采用这种架构模式时,系统一般分成4层,分别是
  • 交互层
  • 服务层
  • 领域层
  • 持久层
    此种架构模式一般应用于桌面系统或web应用系统
  1. 客户/服务端模式
    此种模式一般是由一个服务端和多个客户端构成,服务端监听客户端的请求并响应。
    此种架构模式一般应用于邮箱系统和银行系统
  2. 主从架构模式
    此架构模式包含主从两部分,主机负责给从机分配工作,从机进行计算并返回计算结果给主机
    数据库主从架构和服务总线模式是采用了此模式
  3. 管道过滤器模式
    应用在工作流和代码编译的场景中
  4. 代理模式
    用于适配服务端和客户端,客户端和服务端之间不直接调用,而是通过代理来实现
    此种模式一般应用在消息队列中
  5. 点对点模式
    此种模式中,每个客户端和服务端即作为服务端又作为客户端存在,互相调用,角色动态变化
  6. 事件总线模式
    一般是由四个组件构成:事件源、事件监听、通道、事件总线
    比如安卓系统就是采用次架构模式
  7. 模型视图控制器模式
    经典的mvc模式,包括3个部分:
  • 模型
  • 视图
  • 控制器
    很多web系统采用此模式
  1. 黑板模式
    这是一种对于没有确定解决方案的解决办法,此模式包含3个部分:
  • 黑板
  • 知识源
  • 控制组件
    所有组件都把信息发送到黑板上,所有组件都从黑板上获取信息,并通过与自身的知识源匹配过滤
    应用场景包括:语音识别、车辆跟踪
  1. 翻译模式
    这是一种语言转换或解释的模式,把一种语言翻译成另外一种语言来执行
    应用场景包括:数据库查询、网络协议转换

参考

英文原文

RocketMQ的存储索引的实现方法

RocketMQ存储索引解读

索引结构

索引包括3个部分,分别是Header、Slot、Index。这3个部分是顺序存储的。其中Header的长度为40个字节。

Header

beginTimestamp endTimestamp beginPhyOffset endPhyOffset hashSlotCount indexCount
long long long long int int
8 8 8 8 4 4

Slot

indexCount
int
4

Index

keyHash phyOffset timeDiff slotValue
int long int int
4 8 4 4

索引文件存储的长度为
IndexHeader.INDEX_HEADER_SIZE + (hashSlotNum * hashSlotSize) + (indexNum * indexSize)
默认值为
40 + 5000000 * 4 + 5000000 * 4 * 20
其中文件头的长度为40字节,slot的长度为4字节, index的长度为20字节

Slot和Index的位置算法

1
2
3
4
5
int keyHash = indexKeyHashMethod(key);
int slotPos = keyHash % this.hashSlotNum;
int absSlotPos = IndexHeader.INDEX_HEADER_SIZE + slotPos * hashSlotSize;
int absIndexPos = IndexHeader.INDEX_HEADER_SIZE + this.hashSlotNum * hashSlotSize
+ this.indexHeader.getIndexCount() * indexSize;

Slot和Index的内容

1
2
3
4
5
6
this.mappedByteBuffer.putInt(absIndexPos, keyHash);
this.mappedByteBuffer.putLong(absIndexPos + 4, phyOffset);
this.mappedByteBuffer.putInt(absIndexPos + 4 + 8, (int) timeDiff);
this.mappedByteBuffer.putInt(absIndexPos + 4 + 8 + 4, slotValue);

this.mappedByteBuffer.putInt(absSlotPos, this.indexHeader.getIndexCount());

搜索算法

计算KEY在索引文件中的位置方法如下:

  1. 计算KEY的哈希值
  2. 用计算的结果除以slot的数量,取余
  3. 头文件长度 + 余数 * slot的长度即为slot的位置
  4. slot中存储的值为index的数量
  5. 头文件长度 + slot数量 slot的长度 + index数量 index的长度即为index的位置
  6. 按index的内容取出数据

索引文件名称

索引文件的名称是由时间戳构成的

1
2
3
4
5
6
7
8
String.format("%04d%02d%02d%02d%02d%02d%03d", 
cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH) + 1,
cal.get(Calendar.DAY_OF_MONTH),
cal.get(Calendar.HOUR_OF_DAY),
cal.get(Calendar.MINUTE),
cal.get(Calendar.SECOND),
cal.get(Calendar.MILLISECOND));

优化手段

  1. 服务在启动时会把所有的索引文件加载到内存中
  2. 定期清理过期索引文件
  3. 异步同步索引到磁盘

疑问

  1. slot的作用是什么呢,为什么不直接使用index
  2. 对于KEY的哈希计算有一定的几率计算结果相同,即哈希值相同
  3. 由于代码中把文件锁的代码注释掉了,这样不会有并发问题吗

用到的类

  1. ByteBuffer
  2. MappedByteBuffer
  3. FileChannel
  4. FileLock