分片模式 Sharding Pattern

未匹配的标注

描述

    将一个数据存储到一组水平分区或碎片。存储和访问大量数据时,这个模式可以提高可扩展性。

背景和问题

单一的服务器的数据存储会受到一些限制。
1. 存储空间。
2. 计算资源。
3. 网络带宽。
4. 地理。

垂直扩展和水平扩展

垂直扩展
    通过增加更多的磁盘容量来实现。虽然增加了容量,但是还是会受到处理器,内存,宽带的影响。
水平扩展
    通过增加更多的服务器来实现。理论上这样的扩展几乎是无限的。

解决方案

把数据分配到水平分区或碎片上。

优点

  1. 易扩展。添加额外的存储节点即可。
  2. 成本低。对可扩展的服务器要求较低。
  3. 云服务器距离用户更近。
  4. 资源之间的竞争更少。

分片策略

1. 查找策略。
    实现
        维护请求路由和物理分区之间的映射。
    优点
        添加新的物理分区的时候,不用修改应用程序的代码,直接维护请求路由和物理分区之间的映射即可。
    缺点
        查找碎片的位置需要额外的性能开销。

2. Range范围。
    实现
        不同的时间段的数据放到不同的分区中。
    优点
        容易实现和使用范围查询好。
    缺点
        解决不了分配不均衡的问题,大多数活跃的数据分片都是相邻的。

3. Hash哈希。
    实现
        通过哈希函数计算出请求路由和物理分区的关系。
    优点
        通过计算即可得到结果,没有必要来维护它们的映射。
    缺点
        计算哈希会有额外的性能开销。添加新的物理分区需要重新平衡所有碎片,成本较大。

4. 按照自己业务设计的策略。VIP用户使用高性能数据分区,普通用户使用普通分区等。

注意事项

  1. 分区的数据要保证均匀分布。
  2. 切割分片的维度要稳定。
  3. 要确保分区数据id是唯一的。雪花算法是一个不错的选择。

何时使用

当数据存储的要求超过单个服务器的资源时。

结构中包含的角色

  1. Shard 分片抽象
  2. ConcreteShard 具体分片
  3. ShardStrategy 抽象分片策略
  4. ConcreteShardStrategy 具体分片策略
  5. ShardFacade 分片门面
  6. Application 应用程序

可用到的设计模式思维

  1. 分片使用到分片策略。这个点可以使用策略模式处理。
  2. 整个流程可以看成是应用程序与存储系统的交互。存储系统下有很多存储子系统(分片应用),这里可以使用门面(外观)模式处理。

最小可表达代码

// 分片抽象
abstract class Shard
{
    protected $number;

    public function __construct($number)
    {
        $this->number = $number;
    }

    public function getNumber()
    {
        return $this->number;
    }
}

// 具体分片
class ConcreteShard extends Shard {}


// 抽象分片策略类
abstract class ShardStrategy
{  
    protected $shards = [];

    public function __construct($shards)
    {
        $this->shards = $shards;
    }

    public abstract function algorithm($requestKey) : Shard;
}

// 具体分片策略类
class HashConcreteShardStrategy extends ShardStrategy
{
    public function algorithm($requestKey) : Shard
    {
        $number = $this->makeHash($requestKey);

        foreach ($this->shards as $shard) {
            if ($number == $shard->getNumber()) {
                return $shard;
            }
        }

        exit('找不到分片,报错!');
    }

    protected function makeHash($requestKey)
    {
        return $requestKey * 2;
    }
}

// 分片门面
class ShardFacade
{
    private $shardStrategy;

    public function __construct()
    {
        $this->shardStrategy = new HashConcreteShardStrategy(
            [
                new ConcreteShard(2), new ConcreteShard(4), 
            ]
        );
    }

    public function selectShard($id) : Shard
    {
        return $this->shardStrategy->algorithm($id);
    }

    public function getNumberById($id)
    {
        return $this->selectShard($id)->getNumber();
    }
}

// 应用程序
class Application
{
    public function getNumberById($id)
    {
        return (new ShardFacade)->getNumberById($id);
    }
}

// 运行
$id = 1;
$number = (new Application)->getNumberById($id);
var_dump($number);

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
发起讨论 查看所有版本


暂无话题~