不久前,Vitess已经有了节流功能,本周末我一发现这个消息,就迫不及待地去尝试,并总结我的印象。
设置集群
我们将按照Vitess Operator的入门指南来设置一个虚拟的Vitess集群。
题外话:我发现Vitess Operator非常容易使用;它涵盖了我所有的基本需求,而且它的文档足够好,不必去找资料。
我将使用一个GKE集群,因为这是我最熟悉的,但你也可以使用Minikube或其他Kubernetes产品。
# create a tiny cluster
$ gcloud container clusters create sample-vitess-cluster --cluster-version 1.17 --zone us-east1-b --num-nodes 5
$ git clone git@github.com:vitessio/vitess.git
$ cd vitess/examples/operator
# before running kubectl, make sure to select the context with newly created cluster
# install vitess operator
$ kubectl apply -f operator.yaml
# provision VitessCluster
$ kubectl apply -f 101_initial_cluster.yaml
# port-forward to the cluster
$ ./pf.sh
# install vtctlclient if you haven't yet
$ go get vitess.io/vitess/go/cmd/vtctlclient
# setup the schema
$ vtctlclient ApplySchema -sql="$(cat create_commerce_schema.sql)" commerce
$ vtctlclient ApplyVSchema -vschema="$(cat vschema_commerce_initial.json)" commerce
现在你的集群已经运行了随着pf.sh 的运行,你有端口转发,这应该允许你用mysql -h 127.0.0.1 -P 15306 -u user 连接到它,并探索一些东西。
启用节流器
按照节流器的文档,我们可以发现节流器目前是默认禁用的。我们必须把-enable-lag-throttler 传递给vttablet来启用它。
Vitess操作符让这一切变得非常简单。
diff --git a/examples/operator/101_initial_cluster.yaml b/examples/operator/101_initial_cluster.yaml
index 8df5c19c8..f2e5de108 100644
--- a/examples/operator/101_initial_cluster.yaml
+++ b/examples/operator/101_initial_cluster.yaml
@@ -62,6 +62,7 @@ spec:
vttablet:
extraFlags:
db_charset: utf8mb4
+ "enable-lag-throttler": "true"
resources:
requests:
你可以用我们上面使用的同样的kubectl apply -f 101_initial_cluster.yaml ,应用修改过的YAML。
我们还需要以某种方式让应用程序通过HTTP与vttablet上的节流器端点对话。
默认情况下,Vitess运营商并没有公开它,所以我们将自己创建一个Service 。
apiVersion: v1
kind: Service
metadata:
name: example-vttablet-commerce
spec:
selector:
"planetscale.com/component": vttablet
"planetscale.com/keyspace": commerce
"planetscale.com/cluster": example
ports:
- name: web
port: 15000
protocol: TCP
targetPort: web
- name: grpc
port: 15999
protocol: TCP
targetPort: grpc
- name: metrics
port: 9104
protocol: TCP
targetPort: metrics
请注意,我们的服务特别指向商务钥匙空间的vttablet。这将使我们的应用程序能够与http://example-vttablet-commerce.default.svc.cluster.local:15000/throttler/check 上的节流器端点对话。
如果你愿意,你可以运行kubectl port-forward service/example-vttablet-commerce 15000 ,并浏览http://localhost:15000/,以看到vttablet的内部仪表板。
如果你通过curl或浏览器访问http://localhost:15000/throttler/check,你可以预览我们要从脚本中点击的节流器端点。下面是它的样子。
{
"StatusCode": 200,
"Value": 0.243247,
"Threshold": 1,
"Message": ""
}
当Value 大于Threshold ,你会看到StatusCode 不等于200。这意味着客户端应该节流。
节流的客户端
我们已经准备好了一切--让我们创建一个样本脚本,大量地写入数据库并检查节流情况。我将使用Ruby作为我的首选语言。
为了给数据库带来更大的压力,我们将在脚本中使用多个线程。
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'mysql2'
end
require 'mysql2'
require 'net/http'
require 'json'
THROTTLER_URI = URI('http://example-vttablet-commerce.default.svc.cluster.local:15000/throttler/check').freeze
puts "connecting..."
def db_healthy?
resp = Net::HTTP.get(THROTTLER_URI)
status = JSON.parse(resp)
# Unhealthy would return 429
status.fetch("StatusCode") == 200
end
threads = 20.times.map do
Thread.new do
client = Mysql2::Client.new(
host: "example-vtgate-ae7df4b6.default.svc.cluster.local",
username: "user",
port: 3306
)
loop do
unless db_healthy?
puts "throttling!"
sleep 1
end
values = 1000.times.map do |t|
"(#{rand(1..5)}, 'SKU-1001', #{rand(100..200)})"
end
client.query("insert into corder(customer_id, sku, price) values #{values.join(', ')}")
end
end
end
threads.each(&:join)
脚本为每个线程创建一个MySQL客户端(这一点很重要,因为连接不能被线程共享),每个线程一次批量插入1000条记录。
运行实验
你应该想办法在同一个Kubernetes集群中运行该脚本,可以把它放到现有的应用中,或者建立一个新的Docker镜像。
脚本一运行,你就可以在http://localhost:15000/,关注vttablet的统计数据。在那里你会看到锯齿状的QPS图表。
锯齿状显示,客户端进行写入,然后回退,然后随着数据库健康状况的恢复再次写入。这很有效!
总结
当进行在线模式迁移、写回填或将数据导入数据库时,客户在写之前检查数据库健康状况是很重要的。这个小演示展示了如何利用Vitess给你的东西来实现这一点。请务必阅读描述所有功能的完整指南,所有节流器。
下面是一些我在生产中要注意的事情。
- vttablet运行在MySQL进程的旁边。如果对节流器的HTTP调用会进入一个热点或关键路径,你真的不希望MySQL主机的所有网络带宽被来自各种客户端的对节流器的调用所吃掉。客户端在查询节流器时使用某种缓存是很重要的。例如,freno确实建议使用一个读过的缓存。
- 你的应用程序必须决定它需要点击什么vttablet来检查它是否需要节流。这在某种程度上违背了Vitess的目的,即让客户保持哑巴,不知道DB的拓扑结构。我想最终把节流检查放到
vtgate,在Vitess前面的SQL代理。
总的来说,我很高兴看到Vitess从基础设施的角度使节流等事情变得非常容易。