3 Mart 2022 Perşembe

PlanetScale Vitess Operator

Giriş
operator'ün nasıl kullanılacağı burada

Toplamda 2 tane dosya gerekiyor. Bunlar 
1. operator.yaml ve 
2. 101_initial_cluster.yaml 
dosyaları


Her iki dosya da https://github.com/vitessio/vitess dizininde

Federation veya Multi Region
Ayrıca multi region kullanım için bir video burada, videonun kaynak kodları da burada. Şeklen şöyle. Burada etcd-global-1,etcd-global-2,etcd-global-3 sunucuları görülebilir.


- Google Cloud için bir kullanım burada
- Konuyu açıklayan Vitess Operator Federation yazısına bakabilirsiniz. Açıklaması şöyle. Yani federation için Global Vitess Lockserver gerekir. Bu işlevi de etcd cluster yapar.
Federation allows separate Vitess Operator instances, in separate Kubernetes clusters, to coordinate to deploy and manage a single Vitess Cluster that spans multiple Kubernetes clusters.

Note that this support consists of low-level capabilities that must be combined with additional Kubernetes plug-ins (like some form of cross-cluster LB) and other capabilities (like federated etcd) to assemble a federated system. 
...
The basic principle of Vitess Operator federation is to write a set of VitessCluster object specifications that, when deployed in separate Kubernetes clusters, each bring up and manage the pieces of the Vitess cluster that live in that Kubernetes cluster. These pieces should then have some way to discover each other and connect up to form a single Vitess cluster.

Ordinarily, deploying several VitessCluster CRDs in several different Kubernetes clusters would result in completely independent Vitess clusters that don't know about each other. The key to federation is ensuring that all these Vitess components are pointed at a shared, global Vitess lockserver, which typically takes the form of an etcd cluster.

Once Vitess components are pointed at a shared, global topology service, they will use that to find each other's addresses to perform query routing and set up MySQL replication.


101_initial_cluster.yaml
Bu dosya tamamen Vitess Operator'a özel.İçinde iki tane bölüm var
1. kind : Secret
 MySQL kurulumunda sonra çalıştırılacak SQL cümleleri vardır
Kubernetes Secret -  Gizli Veri yazısına bakabilirsiniz

2. kind: VitessCluster : 
Vitess Cluster'ın kaynaklarının tanımlandığı yer. VitessCluster tanımlamayı Vitess Operator - VitessCluster.yaml yazısına taşım

operator.yaml
Not : İlk kullandığım operator.yaml bir müddet sonra çalışmamaya başladı. Bu yüzden gidip yeni operator.yaml dosyasını indirmek gerekti. Linki burada. Kullandığımız Vitess sürümüne uygun tag'lenmiş dosyayı indirmek gerekiyor. Örneğin
- main ile taglenmiş dosyada "image: planetscale/vitess-operator:latest" yazıyor. 
- ancak "release 14" olarak taglenmiş dosyada "image: planetscale/vitess-operator:v2.7.3" yazıyor

Bu dosyayla ilgili notlarımı Vitess Operator - operator.yaml yazısına taşıdım


Operator Çalışırken
Vitess Operator vitess kullanımı için gerekli her şeyi çalıştırır. Yani önce Vitess Operator'ün çalıştırılması gerekir. Eğer Vitess Operator düzgün başlamazsa, vtablet, vtgate gibi hiç bir şey de başlamaz. Çıktısı şöyle
>kubectl apply -f operator.yaml
customresourcedefinition.apiextensions.k8s.io/etcdlockservers.planetscale.com created
customresourcedefinition.apiextensions.k8s.io/vitessbackups.planetscale.com created
customresourcedefinition.apiextensions.k8s.io/vitessbackupstorages.planetscale.com created
customresourcedefinition.apiextensions.k8s.io/vitesscells.planetscale.com created
customresourcedefinition.apiextensions.k8s.io/vitessclusters.planetscale.com created
customresourcedefinition.apiextensions.k8s.io/vitesskeyspaces.planetscale.com created
customresourcedefinition.apiextensions.k8s.io/vitessshards.planetscale.com created
serviceaccount/vitess-operator created
role.rbac.authorization.k8s.io/vitess-operator created
rolebinding.rbac.authorization.k8s.io/vitess-operator created
deployment.apps/vitess-operator created
priorityclass.scheduling.k8s.io/vitess-operator-control-plane created
priorityclass.scheduling.k8s.io/vitess created
Örnek
Operator çalışırken podu şöyle görürüz. Yani ContainerCreating ve Running aşamalarından geçiyor.
default       vitess-operator-7794c74b9b-5hcxn   0/1     ContainerCreating   0             8s
daha sonra
default       vitess-operator-7794c74b9b-5hcxn   1/1     Running   	     0             97s
Operator çalıştıktan sonra şöyle yaparız
$ kubectl get pods
NAME                                             READY   STATUS    RESTARTS   AGE
...
vitess-operator-8454d86687-4wfnc                 1/1     Running   0          2m29s

Minikube İle Kullanım
Talimatlar burada. Eğer .sh dosyalarını hesaba katarsak bu örnek sadece Linux'ta çalışıyor. Katmazsak Windows'ta da çalışır. 

Vitess örneğindeki "--kubernetes-version=v1.19.16" seçeneğini benim minikube kabul etmedi
minikube start --cpus=4 --memory=4000 --disk-size=32g kubectl apply -f operator.yaml
Daha sonra cluster'ı başlatmak için şöyle yaparız. Yani examples/operator altındaki dosyalar kullanılıyor. Bu dosyalar kubernetes dosyaları. examples/local dizinindeki gibi "sh" dosyaları değil.
cd vitess/examples/operator
kubectl apply -f 101_initial_cluster.yaml
Bu işlemden sonra her şeyin çalışması için yaklaşık  7-8 dakika beklemek gerekiyor. Cluster'ın çalıştığını kontrol ederiz. İki tane tablet çalışması lazım. Çünkü yaml dosyası şöyle
tabletPools:
  - cell: zone1
    type: replica
    replicas: 2
Zaten pod çıktısında da bunu görebiliriz. Her pod içinde 3 tane container çalışıyor.
$ kubectl get pods
NAME                                             READY   STATUS    RESTARTS   AGE
example-etcd-faf13de3-1                          1/1     Running   0          78s
example-etcd-faf13de3-2                          1/1     Running   0          78s
example-etcd-faf13de3-3                          1/1     Running   0          78s
example-vttablet-zone1-2469782763-bfadd780       3/3     Running   1          78s
example-vttablet-zone1-2548885007-46a852d0       3/3     Running   1          78s
example-zone1-vtctld-1d4dcad0-59d8498459-kwz6b   1/1     Running   2          78s
example-zone1-vtgate-bc6cde92-6bd99c6888-vwcj5   1/1     Running   2          78s
vitess-operator-8454d86687-4wfnc                 1/1     Running   0          2m29s
Eğer 2 tane cell açarsak çıktı şöyle. Halen 3 tane etcd çalışıyor. Her cell için 2 tane yani toplam 4 tane vtctld çalışıyor
kubectl get pods
NAME                                                      READY   STATUS    RESTARTS       AGE
adv-vitess-cluster-az1-vtctld-a22f4b1a-86f6d4b78c-ldz9h   1/1     Running   3 (2m6s ago)   10m
adv-vitess-cluster-az1-vtctld-a22f4b1a-86f6d4b78c-vwdhp   1/1     Running   4 (105s ago)   10m
adv-vitess-cluster-az1-vtgate-498e7697-5458d77dc8-mr6pn   1/1     Running   4 (2m3s ago)   10m
adv-vitess-cluster-az1-vtgate-498e7697-5458d77dc8-thgmg   1/1     Running   4 (102s ago)   10m
adv-vitess-cluster-az2-vtctld-d97301ea-764d4ddc6c-d7fpq   1/1     Running   3 (2m3s ago)   10m
adv-vitess-cluster-az2-vtctld-d97301ea-764d4ddc6c-jkmzd   1/1     Running   4 (104s ago)   10m
adv-vitess-cluster-az2-vtgate-9ea92c94-6cc44cd6b-5jcqm    1/1     Running   4 (113s ago)   10m
adv-vitess-cluster-az2-vtgate-9ea92c94-6cc44cd6b-pltm2    1/1     Running   4 (111s ago)   10m
adv-vitess-cluster-etcd-07a83994-1                        1/1     Running   1 (116s ago)   10m
adv-vitess-cluster-etcd-07a83994-2                        1/1     Running   1 (113s ago)   10m
adv-vitess-cluster-etcd-07a83994-3                        1/1     Running   1 (110s ago)   10m
adv-vitess-cluster-vttablet-az1-1330809953-8066577e       3/3     Running   2 (2m ago)     10m
adv-vitess-cluster-vttablet-az1-3415112598-0c0e8ee0       3/3     Running   2 (119s ago)   10m
adv-vitess-cluster-vttablet-az1-4135592426-c2dc2c3d       3/3     Running   2 (112s ago)   10m
adv-vitess-cluster-vttablet-az2-0915606989-18937e48       3/3     Running   2 (117s ago)   10m
adv-vitess-cluster-vttablet-az2-1366268705-cdd98d67       3/3     Running   2 (114s ago)   10m
adv-vitess-cluster-vttablet-az2-4058700183-5f0ba1e4       3/3     Running   2 (115s ago)   10m
vitess-operator-7794c74b9b-s6gc8                          1/1     Running   0              11m
Bunu görmek için şöyle yaparız. Bu container isimleri şöyle vttablet, mysqld, mysqld-exporter.
$ kubectl logs example-vttablet-zone1-2469782763-bfadd780
error: a container name must be specified 
for pod example-vttablet-zone1-2469782763-bfadd780, 
choose one of: [vttablet mysqld mysqld-exporter] 
or one of the init containers: [init-vt-root init-mysql-socket]
Ya da şöyle yaparız
$ kubectl get pods example-vttablet-zone1-2548885007-46a852d0 -o jsonpath={.spec.containers[*].name}
vttablet mysqld mysqld-exporter
Eğer bir container'ın loglarına bakmak istersek şöyle yaparız. Burada vtablet'in loglarına bakıyoruz
kubectl logs example-vttablet-zone1-2469782763-bfadd780 -c vttablet
Eğer bir pod'da problem varsa bakmak için şöyle yaparız
kubectl describe pods <podname>
Port Forward
Bu işlemi dışarıdan mysql client ile bağlanabilmek için yapmak gerekiyor. Şöyle yaparız
./pf.sh &
alias vtctlclient="vtctlclient -server=localhost:15999"
alias mysql="mysql -h 127.0.0.1 -P 15306 -u user"
pf.sh dosyasının içi şöyle
#!/bin/sh

kubectl port-forward --address localhost "$(kubectl get service --selector="planetscale.com/component=vtctld" -o name | head -n1)" 15000 15999 &
process_id1=$!
kubectl port-forward --address localhost "$(kubectl get service --selector="planetscale.com/component=vtgate,!planetscale.com/cell" -o name | head -n1)" 15306:3306 &
process_id2=$!
sleep 2
echo "You may point your browser to http://localhost:15000, use the following aliases as shortcuts:"
echo 'alias vtctlclient="vtctlclient -server=localhost:15999 -logtostderr"'
echo 'alias mysql="mysql -h 127.0.0.1 -P 15306 -u user"'
echo "Hit Ctrl-C to stop the port forwards"
wait $process_id1
wait $process_id2
VtGate için cluster içindeki 3306 MySQL portu dış dünyaya 15306 olarak açılıyor
Topology Server için cluster içindeki 15000 ve 15999 portları da dış dünyaya yine aynı numaralarla açılıyor. 15000 HTTP için 15999 ise gRPC için. Böylece dış dünyadan da vtctlclient kullanılabilir.

Topology Server
Topology Server yazısına taşıdım

VTGate
İki cell ile şöyle görürüz. az1 içinde 3 tablet var. İki tanesi replica bir tanesi readonly. az2 içinde de 3 tablet var. Bir tanesi primary, bir tanesi replica ve 1 tanesi de readonly.

Çünkü bu pod şöyle çalıştırılıyor. Yani kendisi az1 içinde ama az2 içindeki tabletleri görüyor. Ayrıca "adv-vitess-cluster-etcd-07a83994-client" isimli ClusterIP servisi kullanarak global etcd sunucusuna da erişiyor. Gerçi parametrede fazladan ".default.svc:2379" var ama sebebini bilmiyorum. Ayrıca bir de "adv-vitess-cluster-etcd-07a83994-peer" isimli ClusterIP servisi var. Bunun da ne olduğunu bilmiyorum.
--buffer_max_failover_duration=10s
--buffer_min_time_between_failovers=20s --buffer_size=1000 --cell=az1 --cells_to_watch=az1,az2 --enable_buffer=true --grpc_max_message_size=67108864 --grpc_port=15999 --logtostderr=true --mysql_auth_server_impl=static --mysql_auth_server_static_file=/vt/secrets/vtgate-static-auth/users.json --mysql_auth_static_reload_interval=30s --mysql_server_port=3306 --mysql_server_version=8.0.13-Vitess --port=15000 --service_map=grpc-vtgateservice --tablet_types_to_wait=MASTER,REPLICA --topo_global_root=/vitess/adv-vitess-cluster/global --topo_global_server_address=adv-vitess-cluster-etcd-07a83994-client.default.svc:2379 --topo_implementation=etcd2
MySQL Sürümü
vitess/lite:latest MySQL 5.7 kullanıyor. Buradan görülebilir. Dosyanın ilk hali şöyle
apiVersion: planetscale.com/v2
kind: VitessCluster metadata: name: example spec: images: vtctld: vitess/lite:latest vtgate: vitess/lite:latest vttablet: vitess/lite:latest vtbackup: vitess/lite:latest mysqld: mysql56Compatible: vitess/lite:latest mysqldExporter: prom/mysqld-exporter:v0.11.0 cells: - name: zone1 gateway: authentication: static: secret: name: example-cluster-config key: users.json replicas: 1 extraFlags: mysql_server_version: "8.0.13-Vitess" resources: requests: cpu: 100m memory: 256Mi limits: memory: 256Mi
MySQL 8 kullanmak için şöyle yaparız. Yani 
- image olarak "vitess/lite:v12.0.0" veya "vitess/lite:mysql80" kullanıyoruz. 
- mysql56Compatible satırını değiştiriyoruz
- extraFlags altına mysql_server_version alanını ekliyoruz.
apiVersion: planetscale.com/v2 kind: VitessCluster metadata: name: example spec: images: vtctld: vitess/lite:mysql80 vtgate: vitess/lite:mysql80 vttablet: vitess/lite:mysql80 vtbackup: vitess/lite:mysql80 mysqld: mysql80Compatible: vitess/lite:mysql80 mysqldExporter: prom/mysqld-exporter:v0.11.0 cells: - name: zone1 gateway: authentication: static: secret: name: example-cluster-config key: users.json replicas: 1 extraFlags: mysql_server_version: "8.0.13-Vitess" resources: requests: cpu: 100m memory: 256Mi limits: memory: 256Mi
Bu durumda tablet'ler sağlıklı başlamadı. Çıktı şöyle. STATUS alanında Running görünüyor ancak READY sayısı 1/3. Yani STATUS ve READY farklı şeyler
$ kubectl get pods
NAME                                             READY   STATUS    RESTARTS      AGE
example-etcd-faf13de3-1                          1/1     Running   1 (10m ago)   17m
example-etcd-faf13de3-2                          1/1     Running   1 (10m ago)   17m
example-etcd-faf13de3-3                          1/1     Running   1 (10m ago)   17m
example-vttablet-zone1-1168688798-4251d3e4       1/3     Running   2 (10m ago)   17m
example-vttablet-zone1-1385747125-70285362       1/3     Running   2 (10m ago)   17m
example-vttablet-zone1-2469782763-bfadd780       1/3     Running   2 (10m ago)   17m
example-vttablet-zone1-2548885007-46a852d0       1/3     Running   2 (10m ago)   17m
example-vttablet-zone1-3798380744-870319fc       1/3     Running   2 (10m ago)   17m
example-zone1-vtctld-1d4dcad0-5d7ffbfc65-bqkkb   1/1     Running   3 (10m ago)   17m
example-zone1-vtgate-bc6cde92-6dd4b45794-5gqdh   1/1     Running   3 (10m ago)   17m
vitess-operator-5f47c6c45d-v7pn6                 1/1     Running   0             18m
Hatanın ne olduğun bakmak için sanırım şöyle yapılabilir. Pod'un neden schedule edilmediği görülebilir.
kubectl get events
mysqld-exporter başladı ama vttablet, ve mysqld başlamadı. Hata şöyle
E0317 08:36:11.606146       1 srv_vschema.go:207] node doesn't exist: /vitess/example/global/cells/zone1/CellInfo: UpdateSrvVSchema(zone1) failed
F0317 08:36:11.606193       1 vttablet.go:109] failed to parse -tablet-path or initialize DB credentials: node doesn't exist: /vitess/example/global/cells/zone1/CellInfo
initeKeyspaceShardTopo: failed to RebuildSrvVSchema
mysqld'nin hatası şöyle
I0317 08:35:57.155966       1 mysqld.go:398] Mysqld.Start(1647506156) stderr: 2022-03-17T08:35:57.150820Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.23) starting as process 567
I0317 08:35:57.157253       1 mysqld.go:398] Mysqld.Start(1647506156) stderr: 2022-03-17T08:35:57.157109Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
I0317 08:35:57.682198       1 mysqld.go:398] Mysqld.Start(1647506156) stderr: Killed
I0317 08:35:57.685847       1 mysqld.go:404] Mysqld.Start(1647506156) stdout: 2022-03-17T08:35:57.685469Z mysqld_safe mysqld from pid file /vt/vtdataroot/vt_1168688798/mysql.pid ended
I0317 08:35:57.685880       1 mysqld.go:398] Mysqld.Start(1647506156) stderr: 2022-03-17T08:35:57.685469Z mysqld_safe mysqld from pid file /vt/vtdataroot/vt_1168688798/mysql.pid ended
I0317 08:35:57.686575       1 mysqld.go:417] Mysqld.Start(1647506156) exit: <nil>
Daha sonra şöyle yaptım ama yine hatayı bulamadım
$ minikube ssh --user root 
docker@minikube $ docker ps
docker@minikube $ sudo docker exec -it FQDN_CONTAINER bash
vitess@example-vttablet-zone1-1385747125-70285362:/$ 

 /vt/bin/mysqlctld \
   --db-config-dba-uname=vt_dba \
      --db_charset=utf8mb4 \
      --init_db_sql_file=/vt/secrets/db-init-script/init_db.sql \
      --logtostderr=true \
      --mysql_socket=/vt/socket/mysql.sock \
      --socket_file=/vt/socket/mysqlctl.sock \
      --tablet_uid=1385747125 \
      --wait_time=2h0m0s
Ve en sonunda anladım ki bunların hiçbir şeyler alakası yok:) MySQL 8 için daha fazla bellek vermek gerekiyormuş. Son hali şöyle oldu
apiVersion: planetscale.com/v2
kind: VitessCluster
metadata:
  name: example
spec:
  images:
    vtctld: vitess/lite:mysql80
    vtgate: vitess/lite:mysql80
    vttablet: vitess/lite:mysql80
    vtbackup: vitess/lite:mysql80
    mysqld:
      mysql80Compatible: vitess/lite:mysql80
    mysqldExporter: prom/mysqld-exporter:v0.11.0
  cells:
  - name: zone1
    gateway:
      authentication:
        static:
          secret:
            name: example-cluster-config
            key: users.json
      replicas: 1
      extraFlags:
        mysql_server_version: "8.0.13-Vitess"
      resources:
        requests:
          cpu: 100m
          memory: 256Mi
        limits:
          memory: 256Mi
  vitessDashboard:
    cells:
    - zone1
    extraFlags:
      security_policy: read-only
    replicas: 1
    resources:
      limits:
        memory: 128Mi
      requests:
        cpu: 100m
        memory: 128Mi

  keyspaces:
  - name: ADV
    turndownPolicy: Immediate
    partitionings:
    - equal:
        parts: 1
        shardTemplate:
          databaseInitScriptSecret:
            name: example-cluster-config
            key: init_db.sql
          replication:
            enforceSemiSync: false
          tabletPools:
          - cell: zone1
            type: replica
            replicas: 1
            vttablet:
              extraFlags:
                db_charset: utf8mb4
              resources:
                limits:
                  memory: 256Mi
                requests:
                  cpu: 100m
                  memory: 256Mi
            mysqld:
              resources:
                limits:
                  memory: 1024Mi
                requests:
                  cpu: 100m
                  memory: 512Mi
              configOverrides: |
                [mysqld]
                lower_case_table_names = 1
            dataVolumeClaimTemplate:
              accessModes: ["ReadWriteOnce"]
              resources:
                requests:
                  storage: 1Gi
EnforceSemiSync alanının açıklaması şöyle. Yani eğer 3 tane replica varsa kullanılabilir. Asynchronous replication olmasına izin vermez.
EnforceSemiSync means Vitess will configure MySQL to require semi-sync acknowledgement of all transactions while forbidding fallback to asynchronous replication under any circumstance.
...
WARNING: Do not enable this if the shard has fewer than 3 master-eligible replicas, as that may lead to master unavailability during routine maintenance.

Örnek
Bir sefer de bir availability zone pod'ları kubernetes açılırken "Pending" olarak kaldı, çünkü Kubernetes cluster'da yeterli kaynak yoktu. Bu durumda da çalışan container sayısı 2/3 görünüyordu. Çalışan container sayısı her zaman 3/3 görünmeli. Her hangi bir tablette bile 2/3 görünse bir yerde mutlaka problem vardır. Read durumuna geçmeyen şey vttablet idi, çünkü sanırım operator cell 2'nin çalışmasını beklediği için vttablet'i de hazır duruma geçirmedi. Çıktı şöyle
$ oc -n rlwy03 get pods
NAME                                                            READY   STATUS             RESTARTS        AGE
adv-vitess-cluster-az1-vtctld-a22f4b1a-6947f5bbb6-627hb         1/1     Running            0               3m40s
adv-vitess-cluster-az1-vtctld-a22f4b1a-6947f5bbb6-86t4t         1/1     Running            1 (3m16s ago)   3m40s
adv-vitess-cluster-az1-vtgate-498e7697-74c5dd4fdc-9rtr5         1/1     Running            2 (3m10s ago)   3m40s
adv-vitess-cluster-az1-vtgate-498e7697-74c5dd4fdc-hfhmc         1/1     Running            2 (3m8s ago)    3m40s
adv-vitess-cluster-az2-vtctld-d97301ea-6fcd788464-w4ppn         1/1     Running            2 (3m10s ago)   3m39s
adv-vitess-cluster-az2-vtctld-d97301ea-6fcd788464-z7bzq         1/1     Running            0               3m40s
adv-vitess-cluster-az2-vtgate-9ea92c94-85587bb7f7-cddb7         1/1     Running            0               3m40s
adv-vitess-cluster-az2-vtgate-9ea92c94-85587bb7f7-f66zb         1/1     Running            2 (3m8s ago)    3m40s
adv-vitess-cluster-etcd-07a83994-1                              1/1     Running            0               3m40s
adv-vitess-cluster-etcd-07a83994-2                              1/1     Running            0               3m40s
adv-vitess-cluster-etcd-07a83994-3                              1/1     Running            0               3m40s
adv-vitess-cluster-vttablet-az1-1330809953-8066577e             2/3     Running            2 (3m8s ago)    3m40s
adv-vitess-cluster-vttablet-az1-3415112598-0c0e8ee0             2/3     Running            1 (2m45s ago)   3m40s
adv-vitess-cluster-vttablet-az1-4135592426-c2dc2c3d             0/3     Pending            0               3m40s
adv-vitess-cluster-vttablet-az2-0915606989-18937e48             2/3     Running            2 (3m11s ago)   3m40s
adv-vitess-cluster-vttablet-az2-1366268705-cdd98d67             0/3     Pending            0               3m40s
adv-vitess-cluster-vttablet-az2-4058700183-5f0ba1e4             2/3     Running            1 (3m ago)      3m40s
Failover
Açıklaması şöyle. Yani master'a bir annotation veriyoruz. Yeni master seçildikten sonra üzerindeki annotation'ı kaldırmayı unutmamak lazım
... let’s say we think our primary is not in good shape and we’d like to force a failover to the replica. We could use the drain feature of the operator to request a graceful failover to a replica. The operator will choose another suitable replica if one is available, healthy, and not itself drained.
Örnek
Şöyle yaparız
$ kubectl annotate pod <podname> drain.planetscale.com/started="Draining for blog"
pod/example-vttablet-zone1-2469782763-bfadd780 annotated
Master geçişi olduktan sonra şöyle yaparız
$ kubectl annotate pod -l planetscale.com/component=vttablet drain.planetscale.com/started-






Hiç yorum yok:

Yorum Gönder

Soft Delete

Giriş Açıklaması  şöyle When using the soft delete mechanism on the database, you might run into a situation where a record with a unique co...