数据库和Doctrine(转发自http://www.111cn.net/phper/332/85987.htm)

图片 1

  对于其他应用程序来说无比普遍最具挑衅性的任务,就是从数据库中
读取和持久化数据音信。即使symfony完整的框架没有暗中同意集成ORM,可是symfony标准版,集成了重重程序,还自带集成了Doctrine那样
一个库,主要的目标是给开发者一个强有力的工具,让你办事起来更为便于。在本章,你会学会doctrine的大旨见解并且可以领悟什么轻松利用数据库。

The largest single database on earth – Google Spanner.

  Doctrine能够完全退出symfony使用,并且在symfony中是或不是使用也是可选的。本章首要驾驭Doctrine的ORM,其目的是让您的对
象映射到数据库中(如MySQL, PostgreSQL和Microsoft
SQL)。如若您欣赏使用原有的数据库查询,这很简单,可以明白cookbook
中的”How to Use Doctrine DBAL“。
你也得以运用Doctrine
ODM库将数据持久化到MongoDB。越多信息请参阅”DoctrineMongoDBBundle“。

咱俩继续互连网技术架构-分布式存储。

一个简短的例子:一个成品
摸底Doctrine是什么样行事的最简便易行的办法就是看一个实际的接纳。在本章,你需求配备你的数据库,制造一个Product对象,持久化它到数据库并且把它抓取回来。

上文大篇幅介绍了部分分布式存储的论争,偏重理论。可别小看那么些理论,谷歌(Google)的次第神器都以创制在这个理论之上,甚至整个Apache的大数额3剑客项目都以受惠于那些理论。难怪@Tiger大牛讲谷歌靠的是一大批世界一级数据,物理,计算领域的Ph.D.,这么些大神以及他们的Paper是谷歌为什么是谷歌(Google)的来由,以及谷歌没有开源为何如故有力的来头,其幕后有着强大的底子切磋社团。

陈设数据库

总目录

在您真的开首以前,你必要配备你的数据库链接音信。按照规矩,那几个信息一般配置在app/config/parameters.yml文件中:

分布式存储概述

# app/config/parameters.yml
parameters:
    database_driver:    pdo_mysql
    database_host:      localhost
    database_name:      test_project
    database_user:      root
    database_password:  password

# ...

分布式存储本性 - 哈希分布/一致性哈希分布

 将配置音信定义到parameters.yml仅仅是一个规矩。定义在该公文中的配置信息将会被主配置文件在装置Doctrine时引用。

分布式存储协议 - 两等级与Paxos

# app/config/config.yml
doctrine:
    dbal:
        driver:   "%database_driver%"
        host:     "%database_host%"
        dbname:   "%database_name%"
        user:     "%database_user%"
        password: "%database_password%"

分布式文件系统 - 谷歌 GFS

由此把数据库音讯分别到一个特定的文件中,你可以很不难的为逐个服务器保存差其他版本。你也足以在档次外轻松存储数据库配置(一些灵活新闻),就好像apache配置一样。更多新闻请参阅How
to Set external Parameters in the Service Container.
今昔Doctrine知道你的数据库配置了,你可以用它来创设一个数据库了。

分布式键值系统- Alibaba Tair**

$ php app/console doctrine:database:create

分布式表格系统- Google BigTable /Megastore

安装数据库为UTF8
纵然对于经验丰裕的程序员来说,一个常犯的失实是,在Symfony项目始于后,忘记设置他们的数码库暗中同意字符集和查对规则,仅把半数以上数据库给出的latin类型的核对作为暗中同意。他们恐怕在率先次操作时会记得,但到了背后敲打两行相关的正常命令之后,就完全忘记了。

分布式数据库系统****MySQL Sharding, Google Spanner / F1**

$ php app/console doctrine:database:drop –force
$ php app/console doctrine:database:create
在Doctrine里直接指派默许字符集是无法的,因为doctrine会根据条件安顿,尽大概多地去适应种种“不可知”景况。解决办法之一,是去布署“服务器级别”的默认音信。
设置UTF8为MySql的默认字符集是相当简单的,只要在数据库配置文件中加几行代码就足以了(一般是my.cnf文件)

1. 分布式文件系统

[mysqld]
# Version 5.5.3 introduced “utf8mb4”, which is recommended
collation-server     = utf8mb4_general_ci # Replaces
utf8_general_ci
character-set-server = utf8mb4            # Replaces utf8
大家引进防止使用Mysql的uft8字符集,因为它并不包容4-byte
unicode字符,若是字符串中有那种字符会被清空。可是那种情景被修复了,参考《新型utf8mb4字符集》

GFS 谷歌(Google)文件系统

———————————————新建数据库那段还不如直接在mysql里面操作更便民———————————————–

事关分布式文件系统,当然首推GFS了。GFS是谷歌分布式存储的内核,所有的神器都是赤手空拳在分布式存储之上的,如谷歌BigTable, 谷歌 Megastore, 谷歌(Google) Percolator, MapReduce等。

如若您想要使用SQLite作为数据库,你必要设置path为您的数据库路径

图片 2

# app/config/config.yml
doctrine:
    dbal:
        driver: pdo_sqlite
        path: "%kernel.root_dir%/sqlite.db"
        charset: UTF8

GFS

创制一个实体类

GFS系统节点能够分为三种剧中人物:GFS Master, GFS ChunkServer, GFS Client.

若果你创立一个应用程序,其中多少产品必要出示。即时不考虑Doctrine只怕数据库,你也相应精晓您需求一个Product对象来显现这么些产品。在你的AppBundle的Entity目录下创办一个类。

GFS文件被分开定位大小的数据库,称为Chunk,
由Master分配一个64位全局唯一ID;
ChunkServer(CS)以一般Linux文件情势将chunk存储在磁盘,为了HA,
Chunk被replication,暗中认同3份。

// src/AppBundle/Entity/Product.php
namespace AppBundle\Entity;

class Product
{
    protected $name;
    protected $price;
    protected $description;
}

客户端访问GFS时,首先走访Master,获取CS消息,之后再去访问CS,完毕数据存取。GFS近日重点用于MapReduce,
Bigtable.

如此的类平日被喻为“Entity”,意味着一个基础类保存数据。它们容易来满足你应用程序的事体须要。可是以往它还不大概被保留到数据库中,因为将来它只不过照旧个简易的PHP类。

租约机制(Lease)

只要你学习了Doctrine背后的概念,你可以让Doctrine来为你创造实体类。他会问您有的题材来创建entity:

GFS追加的笔录大小从即是KB到几十MB不等,为了幸免Master变成系统瓶颈,GFS引入了租约机制,即将Chunk的写操作授权给ChunkServer。拥有租约授权的CS称为主ChunkServer。在租约有效期内,如60秒,对该chunk的写操作都由主CS负责。主CS也足以在租约到期后,不断向Master提议续约直到Chunk写满。

$ php app/console doctrine:generate:entity

一致性模型

 添加映射音信

GFS协助一个宽大的一致性模型,GFS从相对必要以及简单化层名考虑,设计成首如果为着追加append而不是为着改写override的架构,如我辈了解的

Doctrine允许你选拔一种越发有意思的办法对数据库举办操作,而不是只是获取基于列表的行到数组中。Doctrine允许你保存整个对象到数据库大概把对象从数据库中取出。那些都是经过映射PHP类到一个数目库表,PHP类的属性对应数据库表的列来落成的。

HBase。

图片 3

看一下记下追加的流水线:

因为Doctrine能够做那几个,所以你只是只须要创造一个meatdata,或然陈设告诉Doctrine的Product类和它的属性应该什么映射到数据库。那几个metadata可以被定义成种种格式,包涵YAML,XML恐怕通过申明直接定义到Product类中。

图片 4

annotations:


// src/AppBundle/Entity/Product.php
namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="product")
 */
class Product
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\Column(type="string", length=100)
     */
    protected $name;

    /**
     * @ORM\Column(type="decimal", scale=2)
     */
    protected $price;

    /**
     * @ORM\Column(type="text")
     */
    protected $description;
}

1)客户端向Master请求chunk各个副本所在CS

一个bundle只好接受一种metadata定义格式。比如,不可以把YAML定义的metadata和申明PHP实体类一起混用。
表名是可选的,若是不难,将基于entity类的名目自动确定。
Doctrine允许你去挑选种种差其他字段类型,逐个字段都有投机的安排。有关字段类型音讯,请看Doctrine
菲尔德 Types Reference。

2)Master再次来到客户端主副本和备副本所在CS地点

你也能够查阅Doctrine官方文档Basic Mapping
Documentation关于映射信息的保有细节。如若你拔取annotations,你需求具备的笺注都有ORM(例如
ORM\Column()),那么些doctrine模板并不曾。你还索要去引入use
Doctrine\ORM\Mapping as ORM;阐明,它是用来推举ORM注册前缀的。
小心你的类名和天性很大概就被映射到一个受有限支撑的SQL字段(如group和user)。举例,假设您的entity类名称为Group,那么,在暗许情状下,你的表名为group,在一部分引擎中或者造成SQL错误。请查看 Reserved SQL
keywords
documentation,他会告诉你哪些科学的躲过那一个名称。此外,你能够无限制简单的映射到差距的表名和字段名,来摘取你的数据库纲要。请查看
Doctrine的Persistent classes和Property Mapping文档。
当使用其余的库大概程序(例如
Doxygen)它们采取了诠释,你应有把@IgnoreAnnotation注释添加到该类上来告诉Symfony忽略它们。
譬如我们要阻拦@fn 注脚抛出非凡,可以这么:

3)客户端将扩大记录发送给每个副本,CS会内部LRU结构缓存这个数量

/**
 * @IgnoreAnnotation("fn")
 */
class Product
// ...

4)当有着副本都确认收到数量,客户端接着发起一个请求控制命令给主副本

生产Getters和Setters
即使Doctrine以往清楚了什么样持久化Product对象到数据库,不过类自身是否有用啊。因为Product仅仅是一个正式的PHP类,你必要创设getter和setter方法(比如getName(),setName())来做客它的性质(因为它的性质是protected),幸运的是
Doctrine可以为大家做这一个:

5)主副本把写请求提交给拥有副本。

$ php app/console doctrine:generate:entities AppBundle/Entity/Product

6)备副本成功做到后应答主副本。

该命令可以确保Product类所有的getter和setter都被转移。这是一个安然无恙的命令行,你可以频仍周转它,它只会转变那一个不存在的getters和setters,而不会交替已有的。

7)主副本响应客户端。

请牢记doctrine
entity引擎生产简单的getters/setters。你应有检查生成的实体,调整getter/setter逻辑为协调想要的。

其中,分为控制流与数据流。

关于doctrine:generate:entities命令
用它你可以生成getters和setters。
用它在配置@ORM\Entity(repositoryClass=”…”)阐明的图景下,生成repository类。
用它可以为1:n可能n:m生成恰当的构造器。
该命令会保存一个原本Product.php文件的备份Product.php~。
有些时候可也可以会促成“不可以再度申明类”错误,你可以放心的去除它,来清除错误。您还足以行使–no-backup选项,来预防发生那一个安顿文件。
本来你未曾要求借助于该命令行,Doctrine不倚重于代码生成,像专业的PHP类,你只需要保险它的protected/private属性拥有getter和setter方法即可。重若是因为用命令行去创制是,一种常见事。
你也可以为一个bundle可能全部实体命名空间内的有所已知实体(任何带有Doctrine映射申明的PHP类)来生成getter和setter:

容错

# generates all entities in the AppBundle
$ php app/console doctrine:generate:entities AppBundle

# generates all entities of bundles in the Acme namespace
$ php app/console doctrine:generate:entities Acme

1)Master容错:

Doctrine不关切你的属性是protected仍然private,或然这个属性是不是有getter或setter。之所以生成这一个getter只怕setter完全是因为您须要跟你的PHP对象进行交换须要它们。
 

与历史观类似,通过操作日志加checkpoint来举行。

创立数量库表和方式
现行大家有了一个可用的Product类和它的映射音信,所以Doctrine知道什么持久化它。当然,今后Product还没有对应的product数据库表在数据库中。幸运的是,Doctrine可以自行成立所有的数据库表。

2)CS容错:

$ php app/console doctrine:schema:update --force

运用复制八个副本方式。

 说真的,那条命令是新鲜的强劲。它会基于你的entities的映照音信,来相比较将来的数据库,并转移所须要的新数据库的更新SQl语句。换句话说,如若你想添加一个新的本性映射元数据到Product并运行该职责,它将生成一个alert
table 语句来添加新的列到已经存在的product表中。
一个更好的表述这一优势的意义是经过migrations,它同意你生成这一个SQL语句。并蕴藏到一个迁移类,并能有社团的运转在你的生育条件中,系统为了安全可相信地跟踪和迁移数据库。
方今你的数据库中有了一个全职能的product表,它的每一种列都会被映射到你指定的元数据。

从GFS的架构可以见见,GFS是一个颇具杰出可伸张能力并可以活动处理各样非凡的连串。谷歌的系统已初阶就考虑了如河水平扩充,所以持续的系统可以站在巨人的双肩上,如Bigtable建构在GFS之上,Megastore,
Spanner又在

持久化对象到数据库
前日我们有了一个Product实体和与之映射的product数据库表。你可以把多少持久化到数据库里。在Controller内,它卓殊不难。添加上面的办法到bundle的DefaultController中。

Biigtable之上融合了关系型数据库的功力,整个方案华丽,完美。

 

其余,谷歌(Google)的成功经验反过来注脚了单Master是卓有功效的,简化了系统还要落到实处了一致性。

// src/AppBundle/Controller/DefaultController.php

// ...
use AppBundle\Entity\Product;
use Symfony\Component\HttpFoundation\Response;

// ...
public function createAction()
{
    $product = new Product();
    $product->setName('A Foo Bar');
    $product->setPrice('19.99');
    $product->setDescription('Lorem ipsum dolor');

    $em = $this->getDoctrine()->getManager();

    $em->persist($product);
    $em->flush();

    return new Response('Created product id '.$product->getId());
}

2. 分布式键值系统

一经您想演示那几个案例,你须求去成立一个路由指向这些action,让他干活。
本文体现了在控制器中应用Doctrine的getDoctrine()方法。这么些办法是获取doctrine服务最便捷的主意。你能在劳务中的任何其他地点使用doctrine注入该服务。愈来愈多关于广泛自身的劳务新闻,请参阅ServiceContainer。
在探视前边例子的详情:

分布式键值类似于分布式表格模型Bigtable的一种特例。相比出名的有亚马逊Dynamo, Memcache以及国内阿里的Tair系统。

在本节10-13行,你实例化$product对象,就像是其余任何一般的php对象一样。

前二日有同伴关系Tair, 那我们就以Tail来聊天吧。

15行获得doctrine实体管理对象,那是承担处理数据库持久化进度和读取对象的。

Tair分布式系统

16行persist()方法告诉Doctrine去“管理”这么些$product对象。还不曾在数据库中采取过语句。

Tair是阿里/Taobao开发的一个遍布式键/值存储系统,tair分为持久化和非持久化三种方法。非持久化的tair可以当做一个分布式缓存,持久化的tair将数据存放置磁盘,当然tair可以自行备份以避免磁盘损坏等题材。

17行党这些flush()方法被调用,Doctrine会查看它管理的有着目标,是还是不是要求被持久化到数据库。在本例子中,那几个$product对象还从未持久化,所以那么些entity管理就会进行一个insert语句并且会在product表中创建一行数据。

系统架构:

实际上,Doctrine通晓您有所的被管制的实业,当你调用flush()方法时,它会一个钱打二十四个结出装有的更动,并举办最管用的查询只怕。
他利用准备好的缓存略微升高品质。比如,你要持久化总是为100的制品对象,然后调用flush()方法。Doctrine会创设一个唯一的备选语句一碗水端平复使用它插入。
在创建和立异目的时,工作流是均等的。在下一节中,如果记录已经存在数据库中,您将看到Doctrine如何聪明的自行发出一个Update语句。

Doctrine提供了一个类库允许你通过编程,加载测试数据到你的种类。该类库为
DoctrineFixturesBundle(http://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html)

图片 5

从数据库中得到对象

同一,Tair由一个Master和一多级Slave节点组成,称之为Config
Server作为完整的主宰中央,而服务节点为可伸缩的Data Server。Config
Server负责管理所有的data server, 维护其状态音讯。Data
Server则对外提供各类数据服务,并以心跳来将本人音讯上报给config
server。可以见见,Config
Server是骨干控制点,而且是单点,只有主-备形式保证其可信性。

从数据库中收获对象更易于,举个例子,假使你布署了一个路由来,用它的ID突显特定的product。

ConfigServer的功能

public function showAction($id)
{
    $product = $this->getDoctrine()
        ->getRepository('AppBundle:Product')
        ->find($id);

    if (!$product) {
        throw $this->createNotFoundException(
            'No product found for id '.$id
        );
    }

    // ... do something, like pass the $product object into a template
}

1) 通过爱惜和dataserver心跳获知集群中现有节点信息

您可以动用@ParamConverter注释不用编写任何代码就足以兑现均等的机能。更加多新闻请查看FrameworkExtraBundle文档。
当你询问某个特定的出品时,你总是需求选择它的”respository”。你可以认为Respository是一个PHP类,它的绝无仅有工作就是辅助你从某个特定类哪儿得到实体。你可以为一个实体对象访问一个repository对象,如下:

2) 依照现有节点的信息来营造数据在集群中的分布表。

$repository = $this->getDoctrine()
    ->getRepository('AppBundle:Product');

3) 提供数据分布表的查询服务。

内部appBundle:Product是精简写法,你可以在Doctrine中随机使用它来顶替实体类的全限定称号(例如AppBundle\Entity\Product)。只要你的entity在你的bundle的Entity命名空间下它就会做事。你一旦有了Repository,你就能够访问其颇具分类的支持方法了。

4) 调度dataserver之间的数额迁移、复制。

// query by the primary key (usually "id")
$product = $repository->find($id);

// dynamic method names to find based on a column value
$product = $repository->findOneById($id);
$product = $repository->findOneByName('foo');

// find *all* products
$products = $repository->findAll();

// find a group of products based on an arbitrary column value
$products = $repository->findByPrice(19.99);

别的ConfigServer已毕了从布局文件load进节点音讯,然后依据安插的数据分布的桶和需求树立的数额备份数,建立数据分布表,长度为桶数乘以备份数。如近年来有1023个桶,备份3,所以长度为1023*3的数组。数组成分就是数码要存储的主节点信息,下标即桶号码。其中后边的1023*2为备份节点新闻。为了负载均衡,主桶会尽力而为均匀分布到具备节点,备桶则基于政策,如不一致数量大旨来分布。

 当然,你也得以选取复杂的查询,想了然越来越多请阅读Querying for Objects 。
您也足以有效拔取findBy和findOneBy方法的优势,很简单的根据五个规格来收获对象。

DataServer的功能

// query for one product matching by name and price
$product = $repository->findOneBy(
    array('name' => 'foo', 'price' => 19.99)
);

// query for all products matching the name, ordered by price
$products = $repository->findBy(
    array('name' => 'foo'),
    array('price' => 'ASC')
);

1) 提供仓储引擎

当你去渲染页面,你可以在网页调试工具的右下角看到不少的询问。
doctrine_web_debug_toolbar
如若你单机该图标,分析页面将打开,展现你的确切查询。
即使你的页面查询超越了50个它会成为紫色。那或然表明你的先后有标题。

2) 接受client的put/get/remove等操作

更新目标
万一您从Doctrine中收获了一个对象,那么更新它就变得很不难了。假如你有一个路由映射一个产品id到一个controller的updateaction。

3) 执行多少迁移,复制等

public function updateAction($id)
{
    $em = $this->getDoctrine()->getManager();
    $product = $em->getRepository('AppBundle:Product')->find($id);

    if (!$product) {
        throw $this->createNotFoundException(
            'No product found for id '.$id
        );
    }

    $product->setName('New product name!');
    $em->flush();

    return $this->redirectToRoute('homepage');
}

4) 插件:在承受请求的时候处理局地自定义作用

更新一个目标包罗三步:

5) 访问计算

1.从Doctrine取出对象
2.修改对象
3.在实体管理者上调用flush()方法

操作规模

留意调用 $em->persist($product)
在此处没有须要。大家想起一下,调用该格局的目的重如果告诉Doctrine来保管照旧“观看”$product对象。在此地,因为您曾经取到了$product对象了,表达已经被管制了。

客户端首先请求Config Server获取数据所在Data Server, 之后向Data
Server发送读写请求。

删去对象

负载均衡

去除一个目的,须要从实体管理者这里调用remove()方法。

Tair选拔分布式一致性哈希算法,可参考大家上一篇介绍,正所谓理论之根本。tair对于所有的key,分配到Q个桶,桶是负载均衡和数目迁移的基本单位。config
server依照已定策略把种种桶指派到不相同的data
server,因为数量根据key做hash算法,所以逐个桶中的数据主导抵消。

$em->remove($product);
$em->flush();

如下图:

正如你想的那样,remove()方法告诉Doctrine你想从数据库中移除指定的实体。真正的删除查询没有被真正的举行,直到flush()方法被调用。

图片 6

询问对象

一致性和可信性:

您曾经见到了repository对象允许你执行一些骨干的查询而不须要您做其他的办事。

分布式系统中的可倚重性和一致性是不可以同时有限支撑的,因为有网络错误.
tair接纳复制技术来压实可相信性,并做了有的优化,当无网络错误的时候,
tair提供的是一种强一致性.可是在有data
server发生故障的时候,客户有只怕在必然时间窗口内读不到最新的数据.甚至发生流行数据丢失的处境.

$repository->find($id);

$repository->findOneByName('Foo');

参考:http://tair.taobao.org/

本来,Doctrine 也同意你利用Doctrine Query
Language(DQL)写一些错综复杂的查询,DQL类似于SQL,只是它用来查询一个大概七个实体类的目的,而SQL则是查询一个数据库表中的行。

3. 分布式表格系统

在Doctrinez中询问时,你有二种选拔:写纯Doctrine查询 或然使用Doctrine的询问创设器。

顾名思义,表格模型,多行多列,通过主键唯一标识。如帝王谷歌 Bigtable

 

Google Bigtable:

利用Doctrine’s Query Builder查询对象
比方你想询问产品,必要回到价格超越19.99的产品,并且须求按价格从低到高排列。你可以应用Doctrine的QueryBuilder:

依据GFS与Chubby的分布式表格系统,目的是涸泽而渔读取速度,许多谷歌(Google)数据如web索引,卫星图像数据都存放在bigtabe。

$repository = $this->getDoctrine()
    ->getRepository('AppBundle:Product');

$query = $repository->createQueryBuilder('p')
    ->where('p.price > :price')
    ->setParameter('price', '19.99')
    ->orderBy('p.price', 'ASC')
    ->getQuery();

$products = $query->getResult();

完全布局:

QueryBuilder对象涵盖了创办查询的享有必须的办法。通过调用getQuery()方法,查询创造器将赶回一个规范的Query对象。它跟大家向来写查询对象效果一样。

(row:string, column:string, timestamp:int64) -> string

纪事setParameter()方法。当Doctrine工作时,外部的值,会通过“占位符”(上面例子的:price)传入,来预防SQL注入攻击。
该getResult()方法重回一个结果数组。想要得到一个结实,你能够采纳getSingleResult()(那么些主意在没有结果时会抛出一个万分)大概getOneOrNullResult():

$product = $query->getOneOrNullResult();

图片 7

更多Doctrine’s Query Builder的新闻请阅读Query Builder。
 

RowKey为任意字符串,长度小于64kb。整个数据依据主键举办排序,字典排序,如若域名的话日常选拔反向变换到排序,那样可以形成二级,子域名可以绵亘不绝。

应用DQL查询对象

系统架构:

不爱动用QueryBuilder,你还足以一贯利用DQL查询:

$em = $this->getDoctrine()->getManager();
$query = $em->createQuery(
    'SELECT p
    FROM AppBundle:Product p
    WHERE p.price > :price
    ORDER BY p.price ASC'
)->setParameter('price', '19.99');

$products = $query->getResult();

图片 8

比方你习惯了写SQL,那么对于DQL也相应不会感觉目生。它们中间最大的例外就是你须要思考对象,而不是数据库表行。正因为这么,所以你从AppBundle:Product拔取并给它定义别名p。(你看和地方落成的结果同样)。

Bigtable

该DQL语法强大到令人猜忌,允许你轻松地在里边投入实体(稍后会介绍关系)、组等。越来越多音讯请参阅Doctrine
Query Language文档。

总体分为客户端,主控服务器和子表服务器Tablet Server。
Bigtable把大表分割为100-200m的子表tablet。

自定义Repository类

Master:

在下边你已经开端在controller中成立和应用负责的询问了。为了隔离,测试和起用那些查询,一个好的不二法门是为你的实体创制一个自定义的repository类并丰盛相关逻辑查询艺术。

管制所有子表tablet
server,扣篮分配子表给子表服务器,子表合并,以及接受子表差别音信,监控子表服务器,以及在子表达成负载均衡与故障复苏。

要定义repository类,首先需求在你的投射定义中添加repository类的扬言:

Tablet Server:

// src/AppBundle/Entity/Product.php
namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="AppBundle\Entity\ProductRepository")
 */
class Product
{
    //...
}

子表服务器,落到实处子表的装载/卸载,以及表格内容的读写,合并,分歧。其服务的多寡蕴涵操作日志及子表sstable数据,而数据保存于底层GFS中。

然后经过运行跟以前生成丢失的getter和setter方法同样的命令行,Doctrine会为您自动生成repository类。

Chubby:

$ php app/console doctrine:generate:entities AppBundle

谷歌(Google)的分布式服务,zk的鼻祖。底层核心算法就是大家上文提及的Paxos,即一大半派达成一致,类似昨日的英帝国公投脱欧。Chubby作为任何bigtable的着力,假若暴发故障,则整个bigtabe不可用。Chubby为了维持HA,
平日大型安顿社团为两地三数额主导五副本

下边,添加一个新措施findAllOrderedByName()
到新生成的repository类。该办法将查询所有的Product实体,并依照字符顺序排序。

怎么须要多少个副本?

// src/AppBundle/Entity/ProductRepository.php
namespace AppBundle\Entity;

use Doctrine\ORM\EntityRepository;

class ProductRepository extends EntityRepository
{
    public function findAllOrderedByName()
    {
        return $this->getEntityManager()
            ->createQuery(
                'SELECT p FROM AppBundle:Product p ORDER BY p.name ASC'
            )
            ->getResult();
    }
}

辩驳上3个数据主导就曾经很高可用了,为啥要选用5个呢?要是只布置在3个数据主导,一个挂了后剩余多个必须不只怕挂,因为commit成功在Paxos协议里必要至少2节点;但即使第四个节点又挂了那儿就真的无法访问了,为了高可用,所以选择了5个数据基本节点.

 在Repository类中可以经过$this->getEntityManager()方法类获取entity管理。
你就可以像使用暗中认可的不二法门一致拔取那个新定义的格局了:

Chubby在Bigtable中提供了/扶助了以下为主职能:

$em = $this->getDoctrine()->getManager();
$products = $em->getRepository('AppBundle:Product')
    ->findAllOrderedByName();

1)选择并确保同一时间有且只有一个主控服务器master

当使用一个自定义的repository类时,你照样可以访问原本的暗许查找方法,比如find()
和findAll()等。

2)保存bigtable系统引导音信

实业的关联/关联
假诺你应用程序中的产品属于一确定的分类。那时你须求一个分拣目标和一种把Product和Category对象关联在联合的方法。首先大家成立Category实体,我们最终要透过Doctrine来对其展开持久化,所以大家那边让Doctrine来帮我们创制那一个类。

3)合营master发现子表服务器加载与卸载

$ php app/console doctrine:generate:entity \
    --entity="AppBundle:Category" \
    --fields="name:string(255)"

4)获取bigtable的schema音讯以及访问控制信息

该命令行为您生成一个Category实体,蕴含id字段和name字段以及相关的getter和setter方法。

Bigtable

波及映射

分成用户表(User Table), 元数据表(Meta Table)和根表(Root
Table)。客户段查询时,首先访问Chubby读取根表地方,再从根表读取所需元数据子表的岗位。

涉嫌Category和Product七个实体,首先在Category类中创建一个products属性:

复制与一致性:

// src/AppBundle/Entity/Category.php

// ...
use Doctrine\Common\Collections\ArrayCollection;

class Category
{
    // ...

    /**
     * @ORM\OneToMany(targetEntity="Product", mappedBy="category")
     */
    protected $products;

    public function __construct()
    {
        $this->products = new ArrayCollection();
    }
}

Bigtable利用强一致性,同一时刻同一个子表只好被一台tablet
server服务,master须求来控制那种一致性,而那也是经过Chubby的分布式互斥锁机制来确保的。

率先,由于一个Category对象将关系到七个Product对象,一个products数组属性被添加到Category类保存那些Product对象。其次,那不是因为Doctrine必要它,而是因为在应用程序中为每种Category来保存一个Product数组万分有效。

GFS +
Bigtable两层架构以一种优雅的法门兼顾系统的强一致和HA。底层的GFS是弱一致性,可用性和品质很好,然则多客户有增无减可能会并发重复记录等数据不雷同难题;上层的Bigtable通过层层分布式索引使得系统对外表现为强一致。Bigtable最大优势在于线性扩张,单机出现故障,可以将服务(1分钟内)自动迁移到整个集群。

代码中__construct()方法非常主要,因为Doctrine须求$products属性成为一个ArrayCollection对象,它跟数组分外类似,但会灵活一些。要是那让你觉得不舒服,不用操心。试想他是一个数组,你会欣然接受它。
上面注释所用的targetEntity
的值可以行使合法的命名空间引用任何实体,而不只是概念在同一个类中的实体。
固然要提到一个概念在不相同的类仍旧bundle中的实体则要求输入完全的命名空间作为对象实体。
接下去,因为每种Product类能够提到一个Category对象,所有添加一个$category属性到Product类:

Google Megastore:

// src/AppBundle/Entity/Product.php

// ...
class Product
{
    // ...

    /**
     * @ORM\ManyToOne(targetEntity="Category", inversedBy="products")
     * @ORM\JoinColumn(name="category_id", referencedColumnName="id")
     */
    protected $category;
}

Megastore在Bigtable的根底上,提供了数据库功能的支撑,介于关系型数据库与NoSQL之间的囤积。谷歌(Google)在其精晓的Megastore诗歌中指出,传统的关系型数据库在谷歌(Google)已经被否认,如MySQL。昂贵的生意数据库会大幅加大用户在云中大幅布署的总资金。

到方今终止,大家添加了三个新天性到Category和Product类。将来告诉Doctrine来为它们生成getter和setter方法。

Megastore设计原理与精髓在于,可以在广域网中同步复制文件写操作,可承受的延时,辅助数据宗旨的故障迁移。散文还透漏,近期谷歌以及有100多少个生产应用Megastore作为存储服务,其可相信度在99.99%-100%,并且平均读取延迟小于万分之一微秒,写入延迟100-400微秒。

$ php app/console doctrine:generate:entities AppBundle

系统架构如下:

俺们先不看Doctrine的元数据,你今后有两个类Category和Product,并且有所一个一对多的涉及。该Category类包蕴一个
数组Product对象,Product包涵一个Category对象。换句话说,你早已创办了你所急需的类了。事实上把那么些需求的数量持久化到数据库上
是次要的。

图片 9

现行,让大家来探望在Product类中为$category配置的元数据。它报告Doctrine关系类是Category并且它需要保留
category的id到product表的category_id字段。换句话说,相关的分类目的将会被封存到$category属性中,不过在底
层,Doctrine会通过存储category的id值到product表的category_id列持久化它们的关系。

客户端库梅格astore Library:

图片 10

提供应用程序的接口,包涵映射megastore操作到bigtable,事务及出现控制,基于Paxos的复制,将呼吁分发给复制伏务器,通过协调者迅速读写。

Category类中$product属性的元数据配置不是特地重大,它独自是告诉Doctrine去追寻Product.category属性来总结出涉嫌映射是何等。

复制服务器Replication:

在继承在此以前,一定要报告Doctrine添加一个新的category表和product.category_id列以及新的外键。

接受客户端的用户请求并转化到外省机房的bigtable实例搞定跨机房连接数过多的难题。

$ php app/console doctrine:schema:update --force

协调者Coord.

封存相关实业

仓储各个机房本地的实体组是或不是处在最新气象音信,已毕神速读写。

目前让我们来探视Controller内的代码如何处理:

Megastore主要功能分为:映射Megastore到Bigtable;
事务并发控制;跨机房数据复制与读写优化。

 

操作流程:

// ...

use AppBundle\Entity\Category;
use AppBundle\Entity\Product;
use Symfony\Component\HttpFoundation\Response;

class DefaultController extends Controller
{
    public function createProductAction()
    {
        $category = new Category();
        $category->setName('Main Products');

        $product = new Product();
        $product->setName('Foo');
        $product->setPrice(19.99);
        $product->setDescription('Lorem ipsum dolor');
        // relate this product to the category
        $product->setCategory($category);

        $em = $this->getDoctrine()->getManager();
        $em->persist($category);
        $em->persist($product);
        $em->flush();

        return new Response(
            'Created product id: '.$product->getId()
            .' and category id: '.$category->getId()
        );
    }
}

第一分析用户的SQL,接着依据用户定义的Megastore数据模型将sSQL转换为底层对应的Bigtable。

现行,一个独自的行被添加到category和product表中。新产品的product.categroy_id列被设置为新category表中的id的值。Doctrine会为您管理那几个持久化关系。

数量复制Replication

取得相关对象

数码拆分成差其余实体组,逐个实体组内的操作日志选取基于Paxos的办法一并到多少个机房保持强一致性。实体组之间通过分布式队列或然两等级提交协议落到实处分布式事务。

当你必要得到相关的靶蛇时,你的干活流跟在此之前一样。首先取得$product对象,然后访问它的相关Category

图片 11

public function showAction($id)
{
    $product = $this->getDoctrine()
        ->getRepository('AppBundle:Product')
        ->find($id);

    $categoryName = $product->getCategory()->getName();

    // ...
}

如上图所示,Megastore的数量复制是通过paxos举办共同复制的,即只要更新一个数目,所有机房都会开展联合更新,因为运用了paxos协议,所以差别机房真对同一条数据的更新复制到所有机房的翻新顺序都以一致的;同步复制保险了数码的实时可知性,拔取paxos算法则保险了具备机房的换代一致性。

在这么些例子中,你首先依据产品id查询一个Product对象。他一味查询产品数据并把多少给$product对象。接下来,当您调
用$product->getCategory()->getName()
时,Doctrine默默的为你执行了第二次询问,查找一个与该产品有关的category,它生成一个$category对象回来给您。

Megastore紧要革新:

图片 12

1)
包括提议了实体组的数据模型,实体组内部维持了关全面据库的ACID性格,实体组之间保持NoSQL弱一致性,立异的玉石不分了SQL和NoSQL的优势。此外实体组的定义规避了质量杀手Join。

重点的是您很简单的访问到了product的相干category对象。不过category的数目并不会被取出来而直到你请求category的时候。那就是延迟加载。

2)
通过Paxos协议同时保障了高可相信与高可用,既可把数据强同步到多个机房,又做到暴发故障时自动切换不影响读写服务。

您也足以从其余方向进行查询:

分布式存储系统有七个对象:可增添性 +
专职能SQL在Megastore上着力落实了。当然,Megastore也有部分标题,其中部分来源底层Bigtable,如单副本等等。实际上,在谷歌,
Megastore已经不合时宜,并再次开发了一套革命性的分布式系统Spanner用于化解那一个标题。

public function showProductsAction($id)
{
    $category = $this->getDoctrine()
        ->getRepository('AppBundle:Category')
        ->find($id);

    $products = $category->getProducts();

    // ...
}

4. 分布式数据库

在这种情状下,同样的事务发生了。你首先查看一个category对象,然后Doctrine创造了第二次查询来博取与之相关联的有着Product对
象。只有在您调用->getProducts()时才会执行一回。
$products变量是一个由此它的category_id的值跟给定的category对象相关联的具有Product对象的汇集。

关系型数据库会聚了电脑世界的智慧,也为今后互连网,大数量做好了铺垫。在互连网时期,如何水平扩张是价值观关系型数据的最大挑衅。

提到和代理类

MySQL Sharding

“延迟加载”成为或者,是因为Doctrine重临一个代理对象来顶替真正的靶子:

经常水平扩大的做法是应用层根据规则将数据查分到多个分片,分布到多少个数据库节点,并引入一个中间层应用来遮掩后段的拆分细节。

$product = $this->getDoctrine()
    ->getRepository('AppBundle:Product')
    ->find($id);

$category = $product->getCategory();

// prints "Proxies\AppBundleEntityCategoryProxy"
echo get_class($category);

同样,在MySQL Sharding中也是看似:

该代理对象继承了Category对象,从外表到作为都非常像category对象。所不一致的是,通过那一个代理对象,Doctrine可以顺延查询真正的Category对象数据,直到真正需要它时(调用$category->getName())。
Doctrine生成了代办对象并把它存储到cache目录中,固然你大概平素没有发现过它。记住它那一点很要紧。
俺们可以透过join连接来四遍性取出product和category数据。那时Doctrine将会重临真正的Category对象,因为不必要延期加载。

图片 13

join相关记录
在从前的我们的查询中,会发出两回询问操作,三次是赢得原对象,几次是获取涉及对象。

如上图,总体分为:应用端,中间层dbproxy集群,数据库组,元数据服务器等。

请记住,你可以由此网页调试工具查看请求的拥有查询。
本来,如若您想三次访问多少个目的,你可以通过一个join连接来幸免二次询问。把下部的格局添加到ProductRepository类中:

1)应用端/客户端:通过MySQL与客户端交互,帮助JDBC,使得本来单机数据库无缝对接。

// src/AppBundle/Entity/ProductRepository.php
public function findOneByIdJoinedToCategory($id)
{
    $query = $this->getEntityManager()
        ->createQuery(
            'SELECT p, c FROM AppBundle:Product p
            JOIN p.category c
            WHERE p.id = :id'
        )->setParameter('id', $id);

    try {
        return $query->getSingleResult();
    } catch (\Doctrine\ORM\NoResultException $e) {
        return null;
    }
}

2)中间层dbproxy:剖析客户SQL,并转账到后端数据库。解析MySQL协议,执行SQL路由,过滤,读写分离,结果归并,排序以及分组等。此外可以引入LVS(Linux
Virtual Server)举行负荷均衡。

今天你就可以在您的controller中三遍性查询一个产品对象和它关系的category对象音讯了。

3)数据库组dbgroup:种种dbgroup由n台数据库机器组成,一台master,剩余为slave。master负责所有些工作及强一致读,并复制到备机。

public function showAction($id)
{
    $product = $this->getDoctrine()
        ->getRepository('AppBundle:Product')
        ->findOneByIdJoinedToCategory($id);

    $category = $product->getCategory();

    // ...
}

4)元数据服务器:爱慕dbgroup拆分规则并用以dbgroup选主。dbproxy通过元数据服务器拆分规则规定SQL的实践布署。此外利用zk来贯彻八个副本HA。

越多涉及音讯
本节中早就介绍了一个平淡无奇的实业关联,一对多涉及。对于更高级的涉嫌和如何使用任何的涉及(例如
一对一,多对一),请参见 doctrine 的Association Mapping Documentation.

值得注意的是,倘若请求数据只涉嫌一个数码库组,则中间层将请求转载并伺机重临结果给客户端;如涉及八个数据库分组,则由中间层将结果实施统一,分组,排序等操作后再次回到给客户端,中间层协商与MySQL包容,所以透明于客户端。

要是你利用注释,你要求事先在颇具注释加ORM\(如ORM\OneToMany),这个在doctrine官方文档里从未。你还亟需评释use
Doctrine\ORM\Mapping as ORM;才能使用annotations的ORM。

Google Spanner

配置
Doctrine是可观可安插的,不过你或许永远不要关怀他们。要想打听更加多关于Doctrine的配备信息,请查看config
reference。

毕竟到谷歌 Spanner登场了,谷歌(Google)Spanne是谷歌举世级分布式数据库存储系统。Spanner的增加性达到了全世界级,可以扩张数百个数据大旨,数百万台机器,上万亿行记录。

生命周期回调
奇迹你可能要求在一个实体被创立,更新可能去除的内外执行一些操作。这个操作方法处在一个实体不一致的生命周期阶段,所以那么些行为被誉为”生命周期回调“。

图片 14

假诺你用annotations格局,开启一个生命周期回调,需求如下设置:(假诺你不欣赏你也可以动用yaml和xml格局)

Spanner使得分布式技术与数据库技术有机的重组起来,分布式可扩展,而数据库则类关系型数据模型。

/**
 * @ORM\Entity()
 * @ORM\HasLifecycleCallbacks()
 */
class Product
{
    // ...
}

重温CAP理论:

距今您可以告知Doctrine在其他可用的生命周期事件上来执行一个格局了。比如,如若你想在一个新的实体首次被创立时设置成立日期列(created)为当下日子。

// src/AppBundle/Entity/Product.php

/**
 * @ORM\PrePersist
 */
public function setCreatedAtValue()
{
    $this->createdAt = new \DateTime();
}

图片 15

地点的例证如若你已经创办了createdAt属性(为在此处突显)。
于今在实体第五回被封存时,Doctrine会自动调用这些措施使created日期自动安装为当前些天期。

上图的CAP定理是指在网络可能出现分区故障的动静下,一致性和可用性不可得兼。例如在银行等应用领域,一致性是不行重大的。又如我辈纯熟的MongoDB并不协理复杂的工作,只援救少量的原子操作,所以不适用于“转帐”等对作业和一致性须求很高的场子。那就须求要求一个关周到据库来对
交易举行过高级其余操纵。

还有一对其他的生命周期事件,你可以应用它。越多生命周期事件和生命周期回调,请查看Doctrine的Lifecycle
伊夫nts documentation。

Spanner同时帮助同步复制,多版本控制,以及跨数据主导业务,完全打破CAP的束缚,在三者之间完美平衡。无论从学术仍然工程,Spanner可谓一个史无前例的分布式存储系统。Spanner能做到那个,谷歌使用GPS和原子钟完成的岁月API。那几个API能将数据基本之间的时辰共同精确到10ms以内。因而完成了作用:无锁读事务,原子schema修改,读历史数据无block。

生命周期回调和事件监听
只顾到setCreatedValue()方法不需求收取任何参数。那是生命周期回调寻常的做法和常规:生命周期回调应该是粗略方法,更关爱于实体内部传输数据。比如设置一个创设/更新字段,生成一个定量值等。
假诺您须求有些相比大的一言一行活动,像执行日志恐怕发送邮件,你应有登记一个恢弘类作为事件监听器或接收器给它赋予访问所需资源的义务。想询问越来越多,请参阅How
to Register 伊芙nt Listeners and Subscribers.
 

Google F1 RDBMS

Doctrine字段类型参考
Doctrine配备了汪洋可用的字段类型。它们每种都能映射PHP数据类型到一定的列类型,无论你利用什么数据库。对于每一种字段类型,Column
都足以被进一步安排,可以安装length,
nullable行为,name大概其余陈设。想查看越来越多新闻请参阅Doctrine的Mapping
Types documentation。

说到Spanner,
大家不得不提一下F1,赛车?谷歌探讨院推出命名为F1的新数据库,F1是谷歌(Google)全新建立的新RDBMS数据库,作为一种混合型数据库融合了BigTable的高增加性和SQL数据库的可用性和功效性。援救具备伸缩性很强的数据库,而不用转向NoSQL。

 

图片 16

总结

如上图,F1脚下支撑着谷歌(谷歌(Google))的AdWords宗旨业务,
而AdWords的后台F1已经从MySQL分库分表迁移到了Spanner。

有了Doctrine,你可以集中精力到你的目的以及如何把它选拔于您的应用程序中,而无需顾虑数据库持久化。因为Doctrine允许你使用其余的PHP对象保存你的多少并借助映射元数据音信来维系一个对象到特定的数据库表。

F1体系架构及效益:

即便Doctrine围绕着一个简单易行的概念发展而来,不过它不可捉摸的兵不血刃。允许你创制复杂的询问和订阅事件,通过订阅事件你可以在整体持久化进度中履行一些不一的作为。

图片 17

干什么谷歌(Google)还索要F1,而不是都应用BigTable呢?因为BigTable提供的最后一致性,一些急需工作级其余运用不只怕运用。同时BigTable仍然NoSql,而大气的采用场景须求有涉嫌模型。就好像未来大气的互连网商家都应用Mysql而不情愿利用HBase,由此谷歌(Google)才有那么些可扩展数据库的F1.而Spanner就是F1的显要的平底存储技术。

Spanner数据模型

数据模型类似Megastore系统。Spanner的表是层次化的,最尾部是目录表directory,别的表创设时可以行使INTERLEAVE
IN
PARENT表示层次关系。其中目录类似于megastore中的实体组,实际存储时,会将同一个索引的数目放到一起,同一个目录的每一个副本都会分配到平等台机器。由此,针对同一个目录的读写事物常常不会提到跨机器,除非目录非凡非凡之伟大。

图片 18

谷歌全新设计了GFS 2-
Colossus之上,紧要立异了实时性,并支持海量小文件。

Spanner基本概念

Universe:一个Spanner计划实例称之为一个Universe,
近期全世界唯有3个,一个用于支付,一个测试,一个线上。

Zones:逐个zone属于一个多少大旨,而一个多少核心能够涵盖七个zone。跨zone通讯代价较高。

Universe Master:督察那一个实例中的zone级别状态音讯

Placement Driver: 提供跨zone数据迁移

Location Proxy:提供获取数据地点讯息服务;

Spanserver: 提供仓储服务,类似于bigtable中的tablet server

图片 19

Spanner也是透过Paxos协议落到实处跨数据基本四个副本的一致性。每一种主副本所在的spanserver还会完成一个锁用于并发控制。

TrueTime

为了兑现产出,数据库需求给逐个事情分配全局唯一事务ID。然则,在分布式系统中,很难生成全局唯一ID。谷歌(Google)创意的拔取了TrueTime机制。

True提姆e是一个提供当地时间的接口,可以协同满世界时间。这些API的兑现靠的是GPS与原子钟。引入了三种,是避免当GPS受到干扰败北后,原子钟则卓殊稳定,不会出现差错。实际布置中,每一个数据基本都亟需配置Master机器,其余机器则须要Slave来从Master同步。

有了True提姆e, Spanner并可以控制并发,完成外部一致性,帮助以下工作:

读写,只读,快照读,读写作业。

[Google2012] James C. Corbett, Jeffrey Dean, Michael Epstein, etc.
Spanner: Google’s Globally-Distributed Database.OSDI’2012.

大家那些盼望看到类似Spanner和F1的寨子开源产品。当然,在二零一四年以及二〇一八年二〇一五年,大家来看一个近乎于Spanner的开源项目,值得注意的是其小编是前谷歌员工,CockroachDB,华语叫蟑螂?打不死的小强。方今

CockroachDB已经推出Beta版本,并且得到高额风投。

https://www.infoq.com/news/2014/08/CockroachDB

CockroachDB: A Scalable, Geo-Replicated, Transactional Datastore

千古十年,在中原睡眠的时候,美国靠着强大的底蕴探究与高尖工程师在的硅谷打造了一个全新的网络+DT时期;未来十年,在弥利坚人上床的时候,中国的商号也早先大批量强调基础研讨,中国会胜出么?

好了,大家分布式存储到此暂告一段落,写作勤奋,其中参考了汪洋网络资源,包涵英文文档。此文基本上属于周边,入门级小说,小编希望在就学进程中同步享用给极客朋友。

图片 20

关注群众号:技巧极客TechBooster

图片 21

发表评论

电子邮件地址不会被公开。 必填项已用*标注