MariaDB
 sql >> Teknologi Basis Data >  >> RDS >> MariaDB

Pengelompokan Asli ProxySQL dengan Kubernetes

ProxySQL telah mendukung pengelompokan asli sejak v1.4.2. Ini berarti beberapa instance ProxySQL bersifat cluster-aware; mereka mengetahui status satu sama lain dan mampu menangani perubahan konfigurasi secara otomatis dengan menyinkronkan hingga konfigurasi terbaru berdasarkan versi konfigurasi, stempel waktu, dan nilai checksum. Lihat entri blog ini yang menunjukkan cara mengonfigurasi dukungan pengelompokan untuk ProxySQL dan bagaimana Anda dapat mengharapkannya untuk berperilaku.

ProxySQL adalah proxy terdesentralisasi, direkomendasikan untuk digunakan lebih dekat ke aplikasi. Pendekatan ini berskala cukup baik bahkan hingga ratusan node, karena dirancang agar mudah dikonfigurasi ulang saat runtime. Untuk mengelola beberapa node ProxySQL secara efisien, kita harus memastikan perubahan apa pun yang dilakukan pada salah satu node harus diterapkan di semua node di farm. Tanpa pengelompokan asli, seseorang harus mengekspor konfigurasi secara manual dan mengimpornya ke node lain (walaupun, Anda dapat mengotomatiskannya sendiri).

Dalam posting blog sebelumnya, kami telah membahas pengelompokan ProxySQL melalui Kubernetes ConfigMap. Pendekatan ini kurang lebih cukup efisien dengan pendekatan konfigurasi terpusat di ConfigMap. Apa pun yang dimuat ke ConfigMap akan dipasang ke dalam pod. Memperbarui konfigurasi dapat dilakukan melalui pembuatan versi (memodifikasi konten proxysql.cnf dan memuatnya ke ConfigMap dengan nama lain) dan kemudian mendorong ke pod tergantung pada penjadwalan metode Deployment dan strategi pembaruan.

Namun, dalam lingkungan yang berubah dengan cepat, pendekatan ConfigMap ini mungkin bukan metode terbaik karena untuk memuat konfigurasi baru, penjadwalan ulang pod diperlukan untuk me-remount volume ConfigMap dan ini dapat membahayakan layanan ProxySQL secara keseluruhan. Misalnya, katakanlah di lingkungan kita, kebijakan kata sandi ketat kita mengharuskan kedaluwarsa kata sandi pengguna MySQL setiap 7 hari, yang mana kita harus terus memperbarui ProxySQL ConfigMap untuk kata sandi baru setiap minggu. Sebagai catatan tambahan, pengguna MySQL di dalam ProxySQL membutuhkan pengguna dan kata sandi agar sesuai dengan yang ada di server MySQL backend. Di situlah kita harus mulai memanfaatkan dukungan pengelompokan asli ProxySQL di Kubernetes, untuk menerapkan perubahan konfigurasi secara otomatis tanpa kerumitan pembuatan versi ConfigMap dan penjadwalan ulang pod.

Dalam posting blog ini, kami akan menunjukkan cara menjalankan pengelompokan asli ProxySQL dengan layanan tanpa kepala di Kubernetes. Arsitektur tingkat tinggi kami dapat diilustrasikan seperti di bawah ini:

Kami memiliki 3 node Galera yang berjalan pada infrastruktur bare-metal yang diterapkan dan dikelola oleh ClusterControl:

  • 192.168.0.21
  • 192.168.0.22
  • 192.168.0.23

Semua aplikasi kami berjalan sebagai pod di dalam Kubernetes. Idenya adalah untuk memperkenalkan dua instance ProxySQL di antara aplikasi dan cluster database kami untuk berfungsi sebagai proxy terbalik. Aplikasi kemudian akan terhubung ke pod ProxySQL melalui layanan Kubernetes yang akan load balance dan failover di sejumlah replika ProxySQL.

Berikut adalah ringkasan penyiapan Kubernetes kami:

[email protected]:~# kubectl get nodes -o wide
NAME    STATUS   ROLES    AGE     VERSION   INTERNAL-IP       EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
kube1   Ready    master   5m      v1.15.1   192.168.100.201   <none>        Ubuntu 18.04.1 LTS   4.15.0-39-generic   docker://18.9.7
kube2   Ready    <none>   4m1s    v1.15.1   192.168.100.202   <none>        Ubuntu 18.04.1 LTS   4.15.0-39-generic   docker://18.9.7
kube3   Ready    <none>   3m42s   v1.15.1   192.168.100.203   <none>        Ubuntu 18.04.1 LTS   4.15.0-39-generic   docker://18.9.7

Konfigurasi ProxySQL melalui ConfigMap

Mari kita siapkan konfigurasi dasar kita yang akan dimuat ke ConfigMap. Buat file bernama proxysql.cnf dan tambahkan baris berikut:

datadir="/var/lib/proxysql"

admin_variables=
{
    admin_credentials="proxysql-admin:adminpassw0rd;cluster1:secret1pass"
    mysql_ifaces="0.0.0.0:6032"
    refresh_interval=2000
    cluster_username="cluster1"
    cluster_password="secret1pass"
    cluster_check_interval_ms=200
    cluster_check_status_frequency=100
    cluster_mysql_query_rules_save_to_disk=true
    cluster_mysql_servers_save_to_disk=true
    cluster_mysql_users_save_to_disk=true
    cluster_proxysql_servers_save_to_disk=true
    cluster_mysql_query_rules_diffs_before_sync=3
    cluster_mysql_servers_diffs_before_sync=3
    cluster_mysql_users_diffs_before_sync=3
    cluster_proxysql_servers_diffs_before_sync=3
}

mysql_variables=
{
    threads=4
    max_connections=2048
    default_query_delay=0
    default_query_timeout=36000000
    have_compress=true
    poll_timeout=2000
    interfaces="0.0.0.0:6033;/tmp/proxysql.sock"
    default_schema="information_schema"
    stacksize=1048576
    server_version="5.1.30"
    connect_timeout_server=10000
    monitor_history=60000
    monitor_connect_interval=200000
    monitor_ping_interval=200000
    ping_interval_server_msec=10000
    ping_timeout_server=200
    commands_stats=true
    sessions_sort=true
    monitor_username="proxysql"
    monitor_password="proxysqlpassw0rd"
    monitor_galera_healthcheck_interval=2000
    monitor_galera_healthcheck_timeout=800
}

mysql_galera_hostgroups =
(
    {
        writer_hostgroup=10
        backup_writer_hostgroup=20
        reader_hostgroup=30
        offline_hostgroup=9999
        max_writers=1
        writer_is_also_reader=1
        max_transactions_behind=30
        active=1
    }
)

mysql_servers =
(
    { address="192.168.0.21" , port=3306 , hostgroup=10, max_connections=100 },
    { address="192.168.0.22" , port=3306 , hostgroup=10, max_connections=100 },
    { address="192.168.0.23" , port=3306 , hostgroup=10, max_connections=100 }
)

mysql_query_rules =
(
    {
        rule_id=100
        active=1
        match_pattern="^SELECT .* FOR UPDATE"
        destination_hostgroup=10
        apply=1
    },
    {
        rule_id=200
        active=1
        match_pattern="^SELECT .*"
        destination_hostgroup=20
        apply=1
    },
    {
        rule_id=300
        active=1
        match_pattern=".*"
        destination_hostgroup=10
        apply=1
    }
)

mysql_users =
(
    { username = "wordpress", password = "passw0rd", default_hostgroup = 10, transaction_persistent = 0, active = 1 },
    { username = "sbtest", password = "passw0rd", default_hostgroup = 10, transaction_persistent = 0, active = 1 }
)

proxysql_servers =
(
    { hostname = "proxysql-0.proxysqlcluster", port = 6032, weight = 1 },
    { hostname = "proxysql-1.proxysqlcluster", port = 6032, weight = 1 }
)

Beberapa baris konfigurasi di atas dijelaskan per bagian di bawah ini:

variabel_admin

Perhatikan admin_credentials variabel di mana kami menggunakan pengguna non-default yaitu "proxysql-admin". ProxySQL mencadangkan pengguna "admin" default untuk koneksi lokal hanya melalui localhost. Oleh karena itu, kita harus menggunakan pengguna lain untuk mengakses instance ProxySQL dari jarak jauh. Jika tidak, Anda akan mendapatkan kesalahan berikut:

ERROR 1040 (42000): User 'admin' can only connect locally

Kami juga menambahkan cluster_username dan cluster_password nilai di admin_credentials baris, dipisahkan oleh titik koma untuk memungkinkan sinkronisasi otomatis terjadi. Semua variabel diawali dengan cluster_* terkait dengan pengelompokan asli ProxySQL dan sudah cukup jelas.

mysql_galera_hostgroups

Ini adalah arahan baru yang diperkenalkan untuk ProxySQL 2.x (gambar ProxySQL kami berjalan pada 2.0.5). Jika Anda ingin menjalankan ProxySQL 1.x, hapus bagian ini dan gunakan tabel scheduler sebagai gantinya. Kami sudah menjelaskan detail konfigurasi di posting blog ini, Cara Menjalankan dan Mengonfigurasi ProxySQL 2.0 untuk MySQL Galera Cluster di Docker di bawah "Dukungan ProxySQL 2.x untuk Galera Cluster".

server_mysql

Semua baris cukup jelas, yang didasarkan pada tiga server database yang berjalan di MySQL Galera Cluster sebagaimana dirangkum dalam tangkapan layar Topologi berikut yang diambil dari ClusterControl:

proxysql_servers

Di sini kami mendefinisikan daftar rekan ProxySQL:

  • nama host - nama host/alamat IP rekan
  • port - port admin rekan
  • bobot - Saat ini tidak digunakan, tetapi dalam peta jalan untuk penyempurnaan di masa mendatang
  • komentar - Kolom komentar formulir gratis

Di lingkungan Docker/Kubernetes, ada beberapa cara untuk menemukan dan menautkan nama host container atau alamat IP dan memasukkannya ke dalam tabel ini, baik dengan menggunakan ConfigMap, penyisipan manual, melalui skrip entrypoint.sh, variabel lingkungan, atau cara lain. Di Kubernetes, bergantung pada metode ReplicationController atau Deployment yang digunakan, menebak nama host pod yang dapat diselesaikan terlebih dahulu agak rumit kecuali jika Anda menjalankan StatefulSet.

Lihat tutorial ini tentang indeks ordinal pod StatefulState yang menyediakan nama host stabil yang dapat diselesaikan untuk pod yang dibuat. Gabungkan ini dengan layanan tanpa kepala (dijelaskan lebih jauh ke bawah), format nama host yang dapat diselesaikan adalah:

{app_name}-{index_number}.{service}

Di mana {service} adalah layanan tanpa kepala, yang menjelaskan dari mana "proxysql-0.proxysqlcluster" dan "proxysql-1.proxysqlcluster" berasal. Jika Anda ingin memiliki lebih dari 2 replika, tambahkan lebih banyak entri yang sesuai dengan menambahkan nomor indeks menaik relatif terhadap nama aplikasi StatefulSet.

Sekarang kita siap untuk memasukkan file konfigurasi ke ConfigMap, yang akan dipasang ke setiap pod ProxySQL selama penerapan:

$ kubectl create configmap proxysql-configmap --from-file=proxysql.cnf

Verifikasi apakah ConfigMap kami dimuat dengan benar:

$ kubectl get configmap
NAME                 DATA   AGE
proxysql-configmap   1      7h57m

Membuat Pengguna Pemantauan ProxySQL

Langkah selanjutnya sebelum kita memulai penerapan adalah membuat pengguna pemantauan ProxySQL di cluster database kita. Karena kita menjalankan kluster Galera, jalankan pernyataan berikut di salah satu node Galera:

mysql> CREATE USER 'proxysql'@'%' IDENTIFIED BY 'proxysqlpassw0rd';
mysql> GRANT USAGE ON *.* TO 'proxysql'@'%';

Jika Anda belum membuat pengguna MySQL (seperti yang ditentukan di bagian mysql_users di atas), kita juga harus membuatnya:

mysql> CREATE USER 'wordpress'@'%' IDENTIFIED BY 'passw0rd';
mysql> GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpress'@'%';
mysql> CREATE USER 'sbtest'@'%' IDENTIFIED BY 'passw0rd';
mysql> GRANT ALL PRIVILEGES ON sbtest.* TO 'proxysql'@'%';

Itu dia. Kami sekarang siap untuk memulai penerapan.

Menerapkan StatefulSet

Kita akan mulai dengan membuat dua instance ProxySQL, atau replika untuk tujuan redundansi menggunakan StatefulSet.

Mari kita mulai dengan membuat file teks bernama proxysql-ss-svc.yml dan tambahkan baris berikut:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: proxysql
  labels:
    app: proxysql
spec:
  replicas: 2
  serviceName: proxysqlcluster
  selector:
    matchLabels:
      app: proxysql
      tier: frontend
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: proxysql
        tier: frontend
    spec:
      restartPolicy: Always
      containers:
      - image: severalnines/proxysql:2.0.4
        name: proxysql
        volumeMounts:
        - name: proxysql-config
          mountPath: /etc/proxysql.cnf
          subPath: proxysql.cnf
        ports:
        - containerPort: 6033
          name: proxysql-mysql
        - containerPort: 6032
          name: proxysql-admin
      volumes:
      - name: proxysql-config
        configMap:
          name: proxysql-configmap
---
apiVersion: v1
kind: Service
metadata:
  annotations:
  labels:
    app: proxysql
    tier: frontend
  name: proxysql
spec:
  ports:
  - name: proxysql-mysql
    nodePort: 30033
    port: 6033
    protocol: TCP
    targetPort: 6033
  - name: proxysql-admin
    nodePort: 30032
    port: 6032
    protocol: TCP
    targetPort: 6032
  selector:
    app: proxysql
    tier: frontend
  type: NodePort

Ada dua bagian dari definisi di atas - StatefulSet dan Service. StatefulSet adalah definisi dari pod atau replika kita dan titik mount untuk volume ConfigMap kita, yang diambil dari proxysql-configmap. Bagian selanjutnya adalah definisi layanan, di mana kita mendefinisikan bagaimana pod harus diekspos dan dirutekan untuk jaringan internal atau eksternal.

Buat set dan layanan stateful ProxySQL:

$ kubectl create -f proxysql-ss-svc.yml

Verifikasi status pod dan layanan:

$ kubectl get pods,svc
NAME             READY   STATUS    RESTARTS   AGE
pod/proxysql-0   1/1     Running   0          4m46s
pod/proxysql-1   1/1     Running   0          2m59s

NAME                      TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                         AGE
service/kubernetes        ClusterIP   10.96.0.1        <none>        443/TCP                         10h
service/proxysql          NodePort    10.111.240.193   <none>        6033:30033/TCP,6032:30032/TCP   5m28s

Jika Anda melihat log pod, Anda akan melihat bahwa kami dibanjiri dengan peringatan ini:

$ kubectl logs -f proxysql-0
...
2019-08-01 19:06:18 ProxySQL_Cluster.cpp:215:ProxySQL_Cluster_Monitor_thread(): [WARNING] Cluster: unable to connect to peer proxysql-1.proxysqlcluster:6032 . Error: Unknown MySQL server host 'proxysql-1.proxysqlcluster' (0)

Di atas berarti proxysql-0 tidak dapat menyelesaikan "proxysql-1.proxysqlcluster" dan menyambungkannya, yang diharapkan karena kami belum membuat layanan tanpa kepala kami untuk catatan DNS yang akan diperlukan untuk komunikasi antar-ProxySQL.

Layanan Tanpa Kepala Kubernetes

Agar pod ProxySQL dapat menyelesaikan FQDN yang diantisipasi dan terhubung secara langsung, proses penyelesaian harus dapat mencari alamat IP pod target yang ditetapkan dan bukan alamat IP virtual. Di sinilah layanan tanpa kepala muncul. Saat membuat layanan tanpa kepala dengan menyetel "clusterIP=None", tidak ada penyeimbangan beban yang dikonfigurasi dan tidak ada IP cluster (IP virtual) yang dialokasikan untuk layanan ini. Hanya DNS yang dikonfigurasi secara otomatis. Saat Anda menjalankan kueri DNS untuk layanan tanpa kepala, Anda akan mendapatkan daftar alamat IP pod.

Berikut adalah tampilannya jika kita mencari catatan DNS layanan tanpa kepala untuk "proxysqlcluster" (dalam contoh ini kita memiliki 3 instance ProxySQL):

$ host proxysqlcluster
proxysqlcluster.default.svc.cluster.local has address 10.40.0.2
proxysqlcluster.default.svc.cluster.local has address 10.40.0.3
proxysqlcluster.default.svc.cluster.local has address 10.32.0.2

Sementara output berikut menunjukkan catatan DNS untuk layanan standar yang disebut "proxysql" yang diselesaikan ke clusterIP:

$ host proxysql
proxysql.default.svc.cluster.local has address 10.110.38.154

Untuk membuat layanan tanpa kepala dan melampirkannya ke pod, seseorang harus mendefinisikan ServiceName di dalam deklarasi StatefulSet, dan definisi Layanan harus memiliki "clusterIP=None" seperti yang ditunjukkan di bawah ini. Buat file teks bernama proxysql-headless-svc.yml dan tambahkan baris berikut:

apiVersion: v1
kind: Service
metadata:
  name: proxysqlcluster
  labels:
    app: proxysql
spec:
  clusterIP: None
  ports:
  - port: 6032
    name: proxysql-admin
  selector:
    app: proxysql

Buat layanan tanpa kepala:

$ kubectl create -f proxysql-headless-svc.yml

Hanya untuk verifikasi, pada titik ini, kami menjalankan layanan berikut:

$ kubectl get svc
NAME              TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                         AGE
kubernetes        ClusterIP   10.96.0.1       <none>        443/TCP                         8h
proxysql          NodePort    10.110.38.154   <none>        6033:30033/TCP,6032:30032/TCP   23m
proxysqlcluster   ClusterIP   None            <none>        6032/TCP                        4s

Sekarang, periksa salah satu log pod kami:

$ kubectl logs -f proxysql-0
...
2019-08-01 19:06:19 ProxySQL_Cluster.cpp:215:ProxySQL_Cluster_Monitor_thread(): [WARNING] Cluster: unable to connect to peer proxysql-1.proxysqlcluster:6032 . Error: Unknown MySQL server host 'proxysql-1.proxysqlcluster' (0)
2019-08-01 19:06:19 [INFO] Cluster: detected a new checksum for mysql_query_rules from peer proxysql-1.proxysqlcluster:6032, version 1, epoch 1564686376, checksum 0x3FEC69A5C9D96848 . Not syncing yet ...
2019-08-01 19:06:19 [INFO] Cluster: checksum for mysql_query_rules from peer proxysql-1.proxysqlcluster:6032 matches with local checksum 0x3FEC69A5C9D96848 , we won't sync.

Anda akan melihat komponen Cluster dapat menyelesaikan, menghubungkan, dan mendeteksi checksum baru dari rekan lainnya, proxysql-1.proxysqlcluster pada port 6032 melalui layanan tanpa kepala yang disebut "proxysqlcluster". Perhatikan bahwa layanan ini hanya mengekspos port 6032 dalam jaringan Kubernetes, sehingga tidak dapat dijangkau secara eksternal.

Pada titik ini, penerapan kami telah selesai.

Menghubungkan ke ProxySQL

Ada beberapa cara untuk terhubung ke layanan ProxySQL. Koneksi MySQL dengan beban seimbang harus dikirim ke port 6033 dari dalam jaringan Kubernetes dan menggunakan port 30033 jika klien terhubung dari jaringan eksternal.

Untuk terhubung ke antarmuka admin ProxySQL dari jaringan eksternal, kita dapat terhubung ke port yang ditentukan di bagian NodePort, 30032 (192.168.100.203 adalah alamat IP utama host kube3.local):

$ mysql -uproxysql-admin -padminpassw0rd -h192.168.100.203 -P30032

Gunakan clusterIP 10.110.38.154 (didefinisikan di bawah layanan "proxysql") pada port 6032 jika Anda ingin mengaksesnya dari pod lain di jaringan Kubernetes.

Kemudian lakukan perubahan konfigurasi ProxySQL sesuai keinginan dan muat ke runtime:

mysql> INSERT INTO mysql_users (username,password,default_hostgroup) VALUES ('newuser','passw0rd',10);
mysql> LOAD MYSQL USERS TO RUNTIME;

Anda akan melihat baris berikut di salah satu pod yang menunjukkan sinkronisasi konfigurasi selesai:

$ kubectl logs -f proxysql-0
...
2019-08-02 03:53:48 [INFO] Cluster: detected a peer proxysql-1.proxysqlcluster:6032 with mysql_users version 2, epoch 1564718027, diff_check 4. Own version: 1, epoch: 1564714803. Proceeding with remote sync
2019-08-02 03:53:48 [INFO] Cluster: detected peer proxysql-1.proxysqlcluster:6032 with mysql_users version 2, epoch 1564718027
2019-08-02 03:53:48 [INFO] Cluster: Fetching MySQL Users from peer proxysql-1.proxysqlcluster:6032 started
2019-08-02 03:53:48 [INFO] Cluster: Fetching MySQL Users from peer proxysql-1.proxysqlcluster:6032 completed

Perlu diingat bahwa sinkronisasi otomatis hanya terjadi jika ada perubahan konfigurasi pada waktu proses ProxySQL. Oleh karena itu, sangat penting untuk menjalankan pernyataan "LOAD ... TO RUNTIME" sebelum Anda dapat melihat aksinya. Jangan lupa untuk menyimpan perubahan ProxySQL ke dalam disk untuk persistensi:

mysql> SAVE MYSQL USERS TO DISK;

Batasan

Perhatikan bahwa ada batasan untuk pengaturan ini karena ProxySQL tidak mendukung penyimpanan/pengeksporan konfigurasi aktif ke dalam file konfigurasi teks yang dapat kita gunakan nanti untuk memuat ke ConfigMap untuk persistensi. Ada permintaan fitur untuk ini. Sementara itu, Anda dapat mendorong modifikasi ke ConfigMap secara manual. Jika tidak, jika pod terhapus secara tidak sengaja, Anda akan kehilangan konfigurasi saat ini karena pod baru akan di-bootstrap oleh apa pun yang ditentukan dalam ConfigMap.

Terima kasih khusus kepada Sampath Kamineni, yang mencetuskan ide entri blog ini dan memberikan wawasan tentang kasus penggunaan dan implementasi.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Membandingkan Solusi Oracle RAC HA dengan Galera Cluster untuk MySQL atau MariaDB

  2. Cara Melindungi Database MySQL &MariaDB Anda Terhadap Serangan Siber Saat di Jaringan Publik

  3. Bagaimana GREATEST() Bekerja di MariaDB

  4. Perbedaan Antara SYSDATE() dan SEKARANG() di MariaDB

  5. Makan makanan anjing kita sendiri – Menjalankan JIRA di MariaDB