有一天,我接到一个请求,问我是否有Django的经验,能否让它与CockroachDB的多地区功能一起工作。我以前从未听说过Django,但我从不拒绝挑战,所以我接受了。
首先,让我们解释一下什么是Django以及它的用途。
什么是Django,Django的用例有哪些?
Django是一个网络框架,它鼓励Python应用程序的快速开发和简洁、实用的设计。它通过提供一个成熟的模式来设计可扩展的网络应用程序,其中有许多功能是开箱即用的。这有助于防止开发人员花费不必要的时间来 "重新发明轮子",这样他们就可以花更多的时间来编写所需的应用程序。通过启动一个Django项目,你会得到一个网络应用程序的基本布局,你可以开始构建。然而,这并不是一个Django教程,所以我们将跳到眼前的话题:我们如何在Django中使用CockroachDB的多区域功能?
当你扩大使用多区域集群时,你可能需要将某些数据子集保存在特定的地方。将特定的数据保存在特定地理位置的服务器上,也被称为数据归属。CockroachDB使用ALTER DATABASE ... PLACEMENT RESTRICTED 语句对多区域集群中的数据统治有基本的支持。
要跟上博客的步伐,你需要三个Kubernetes集群。理想情况下,这些集群位于不同的区域,但这并不是必须的。你还需要对Docker和Kubernetes有基本了解。
作为一个Django和Python的新手,我选择使用CockroachDB文档中的Django应用实例。这是一个将客户、产品和订单插入CockroachDB数据库的简单应用。
这个博客的最新的多区域代码可以在这里找到。
为了展示CockroachDB的多区域功能,我将更新Django示例程序中的捕获客户的python函数,以记录客户应该居住在哪个云提供商。例如,如果客户 "Mike "是从AWS发布的,那么Mike的客户记录应该保留在该地区的节点上。
需要进行一些更新,以便应用程序接受额外的字段,将云记录到数据库中。需要做一些改变,首先是改变model.py 文件以增加额外的字段。
class Customers(models.Model):
id = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
editable=False)
name = models.CharField(max_length=250)
cloud = models.CharField(max_length=250, null=True)
更新views.py 以接受新的字段。
def post(self, request, *args, **kwargs):
form_data = json.loads(request.body.decode())
name, cloud = form_data['name'], form_data['cloud']
c = Customers(name=name, cloud=cloud)
c.save()
return HttpResponse(status=200)
修改settings.py ,使其具有你的数据库配置。
DATABASES = {
'default': {
'ENGINE': 'django_cockroachdb',
'NAME': 'django',
'USER': 'user',
'PASSWORD': 'password',
'HOST': 'cockroachdb-public',
'PORT': '26257',
# If connecting with SSL, include the section below, replacing the
# file paths as appropriate.
'OPTIONS': {
'sslmode': 'verify-full',
'sslrootcert': '/certs/ca.crt',
# Either sslcert and sslkey (below) or PASSWORD (above) is
# required.
# 'sslcert': '/certs/client.root.crt',
# 'sslkey': '/certs/client.root.key',
},
},
}
最后,在0001_inital.py 文件中添加额外的字段到迁移中。
operations = [
migrations.CreateModel(
name='Customers',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('name', models.CharField(max_length=250)),
('cloud', models.CharField(max_length=250, null=True)),
现在我们有了一个可以部署的应用程序,我们需要准备我们的CockroachDB集群。我们需要做的第一件事是创建一个数据库供应用程序使用。因为我的CockroachDB集群是部署在Kubernetes上的,我将部署一个带有正确证书的安全豆荚来连接并创建一个名为Django的数据库。
CREATE DATABASE django;
现在我们有了一个数据库,我们可以在每个区域部署我们的应用程序。通过这样做,Django将创建所有需要的数据库表等。同样,因为我使用的是Kubernetes,我将直接部署上面git仓库中的清单。确保你设置了上下文并部署到了正确的命名空间。
kubectl apply -f ./kubernetes/deployment.yaml
一旦应用程序部署完毕,负载平衡器服务创建完毕,我们就可以检索外部IP或主机名(如果是AWS的话)来发布我们的数据。在这里,我已经为我的每个上下文和每个命名空间设置了一个环境变量。
az_app_ip=$(kubectl get svc django-service --context $clus1 --namespace $azregion -o json | jq -r '.status.loadBalancer.ingress[0].ip')
aws_app_ip=$(kubectl get svc django-service --context $clus2 --namespace $aws_region -o json | jq -r '.status.loadBalancer.ingress[0].hostname')
gcp_app_ip=$(kubectl get svc django-service --context $clus3 --namespace $gcp_region -o json | jq -r '.status.loadBalancer.ingress[0].ip')
使用应用程序的简单API向数据库添加三个条目。你会注意到第二个字段是 "cloud",用不同的值来表示它被部署到哪个云。
curl --header "Content-Type: application/json" \
--request POST \
--data '{"name":"Carl", "cloud":"azure"}' http://$az_app_ip:8000/customer/
curl --header "Content-Type: application/json" \
--request POST \
--data '{"name":"Mike", "cloud":"aws"}' http://$aws_app_ip:8000/customer/
curl --header "Content-Type: application/json" \
--request POST \
--data '{"name":"Dan", "cloud":"gcp"}' http://$gcp_app_ip:8000/customer/
现在我们在CockroachDB内的django数据库中有了一些数据,我们可以把注意力转移到多区域的能力上。
为了启用多区域配置,需要执行几个简单的步骤。首先是为数据库设置主区域,然后再添加其他区域。在我的案例中,这是Azure的uksouth作为主区域,然后是AWS的eu-west-1和GCP的europe-west4。
ALTER DATABASE django PRIMARY REGION "uksouth";
ALTER DATABASE django ADD REGION "eu-west-1";
ALTER DATABASE django ADD REGION "europe-west4";
对于cockroach_example_customers表,我们想根据云列的值来定位数据。这意味着优化访问数据的正确表定位是REGIONAL BY ROW。这些语句使用CASE语句,将给定的云的数据放在正确的区域中。
ALTER TABLE cockroach_example_customers ADD COLUMN region crdb_internal_region AS (
CASE WHEN cloud = 'aws' THEN 'eu-west-1'
WHEN cloud = 'azure' THEN 'uksouth'
WHEN cloud = 'gcp' THEN 'europe-west4'
END
) STORED;
ALTER TABLE cockroach_example_customers ALTER COLUMN REGION SET NOT NULL;
ALTER TABLE cockroach_example_customers SET LOCALITY REGIONAL BY ROW AS "region";
接下来,运行一个复制报告,看看哪些范围仍然不符合你所期望的定位。
SELECT * FROM system.replication_constraint_stats WHERE violating_ranges > 0;
接下来,运行复制报告文档中建议的查询,该查询应该显示哪些数据库和表的名称包含违规的_ranges。
WITH
partition_violations
AS (
SELECT
*
FROM
system.replication_constraint_stats
WHERE
violating_ranges > 0
),
report
AS (
SELECT
crdb_internal.zones.zone_id,
crdb_internal.zones.subzone_id,
target,
database_name,
table_name,
index_name,
partition_violations.type,
partition_violations.config,
partition_violations.violation_start,
partition_violations.violating_ranges
FROM
crdb_internal.zones, partition_violations
WHERE
crdb_internal.zones.zone_id
= partition_violations.zone_id
)
SELECT * FROM report;
你应该看到cockroach_example_customers表包含违规的范围。现在我们可以启用放置限制,将这些范围重新放置在正确位置的节点上。
ALTER DATABASE django PLACEMENT RESTRICTED;
现在你已经限制了所有区域表的无投票权复制的位置,你可以运行另一个复制报告来查看效果。请耐心等待,因为这可能需要几分钟的时间才能产生效果(需要移动的范围越多,需要的时间越长)。
SELECT * FROM system.replication_constraint_stats WHERE violating_ranges > 0;
作为Python和Django的新手,我发现编辑一个现有的应用程序来展示CockroachDB的多区域功能是很简单的。这向我展示了在Django框架的帮助下开发Python应用程序是多么容易。
使用CockroachDB的数据管理(通俗地说,就是把数据钉在特定的地方)有助于提高读写的性能。将范围钉在特定的位置上,可以减少做出共识决定的往返时间,从而减少写的延迟。这项功能的另一个好处是,通过控制数据的位置,你可以符合数据主权或所有权的立法。所以,如果你想在关系数据库的支持下创建多区域的Python应用程序,Django和CockroachDB是一个很好的组合。
不要忘记我在博客中使用的所有代码都可以在这里找到。