分片模式 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 网站上。

上一篇 下一篇
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 0
发起讨论 只看当前版本


暂无话题~