Salah satu cara untuk meningkatkan performa aplikasi berbasis penampung adalah dengan meningkatkan resource cluster dengan menambahkan node atau menambahkan resource, seperti CPU atau memori, ke node Anda. Namun, pendekatan ini dapat menjadi mahal. Menyesuaikan Node cluster untuk performa yang lebih baik akan membantu Anda mengoptimalkan penggunaan resource untuk workload dengan cara yang hemat biaya. Dokumen ini menjelaskan cara menggunakan Performance Tuning Operator untuk menyesuaikan node pekerja guna mengoptimalkan performa beban kerja untuk Google Distributed Cloud.
Untuk mendapatkan hasil maksimal dari hardware dan software yang mendasarinya, berbagai jenis aplikasi, terutama aplikasi berperforma tinggi, akan mendapatkan manfaat dari penyesuaian setelan node seperti berikut:
- CPU khusus untuk workload yang sensitif terhadap performa
- CPU yang dicadangkan untuk Daemon dan Layanan Kubernetes standar
- Meningkatkan ukuran halaman memori dengan hugepage 1 GiB (gibibyte) atau 2 MiB (mebibyte)
- Distribusi beban kerja berdasarkan arsitektur sistem, seperti prosesor multi-core dan NUMA
Dengan Operator Penyesuaian Performa, Anda mengonfigurasi setelan performa tingkat node dengan membuat resource kustom Kubernetes yang menerapkan konfigurasi performa. Berikut adalah manfaatnya:
Satu antarmuka konfigurasi terpadu: Dengan Performance Tuning Operator, Anda memperbarui satu atau beberapa manifes
PerformanceTuningProfile
yang dapat diterapkan ke node pekerja dengan pemilih node. Anda tidak perlu mengonfigurasi setiap node satu per satu dengan beberapa setelan kebijakan dan konfigurasi. Pendekatan ini memungkinkan Anda mengelola konfigurasi tingkat node dan tingkat penampung dengan cara yang terpadu.Persistensi dan keandalan: Anda juga mendapatkan semua keandalan yang disediakan Kubernetes dengan arsitektur ketersediaan tinggi. Resource kustom
PerformanceTuningProfile
dapat diperbarui kapan saja sesuai keinginan Anda dan setelannya tetap ada di seluruh operasi cluster utama, seperti upgrade.
Operator Penyesuaian Performa berfungsi dengan mengatur fitur dan alat Kubernetes serta sistem operasi (OS) terkait performa berikut:
Untuk mencegah konflik, saat menggunakan Performance Tuning Operator, sebaiknya jangan gunakan alat dan fitur Kubernetes dan OS yang disebutkan sebelumnya secara terpisah.
Prasyarat dan batasan
Berikut adalah prasyarat dan batasan untuk menggunakan Operator Penyesuaian Performa:
Khusus Red Hat Enterprise Linux (RHEL): Operator Penyesuaian Performa hanya didukung untuk node yang menjalankan versi RHEL yang didukung.
Cluster pengguna atau hybrid dengan node pekerja: Operator Penyesuaian Performa hanya didukung untuk digunakan dengan node pekerja di cluster pengguna atau hybrid. Penggunaan Operator Penyesuaian Performa untuk menyesuaikan node bidang kontrol tidak didukung. Operator Penyesuaian Performa menggunakan pemilih node untuk menentukan cara menerapkan profil penyesuaian. Untuk memastikan bahwa profil penyesuaian hanya diterapkan ke node pekerja,
nodeSelector
di setiap resource kustom profil harus menyertakan label node pekerja standarnode-role.kubernetes.io/worker: ""
. JikanodeSelector
dalam profil penyesuaian cocok dengan label di node bidang kontrol, node tersebut tidak disetel dan kondisi error ditetapkan. Untuk informasi selengkapnya tentang kondisi error, lihat Memeriksa status. Pastikan cluster Anda beroperasi dengan benar sebelum menginstal Performance Tuning Operator dan menerapkan profil penyesuaian.TuneD 2.22.0: Operator Penyesuaian Performa memerlukan TuneD versi 2.22.0 untuk diprainstal di node pekerja yang ingin Anda sesuaikan. Untuk informasi tambahan tentang TuneD, termasuk petunjuk penginstalan, lihat Memulai TuneD dalam dokumentasi Red Hat Enterprise Linux. Operator Penyesuaian Performa menggunakan TuneD dengan profil
cpu-partitioning
. Jika tidak memiliki profil ini, Anda dapat menginstalnya dengan perintah berikut:dnf install -y tuned-profiles-cpu-partitioning
Persyaratan resource workload: Untuk mendapatkan hasil maksimal dari penyesuaian performa, Anda harus memiliki pemahaman yang baik tentang persyaratan memori dan CPU (permintaan dan batas resource) untuk workload Anda.
Resource node yang tersedia: Temukan resource CPU dan memori untuk node Anda. Anda bisa mendapatkan informasi CPU dan memori mendetail untuk node di file
/proc/cpuinfo
dan/proc/meminfo
. Anda juga dapat menggunakankubectl get nodes
untuk mengambil jumlah resource komputasi dan memori (status.allocatable
) yang dimiliki node pekerja yang tersedia untuk Pod.Memerlukan pengosongan: Sebagai bagian dari proses penyesuaian, Operator Penyesuaian Performa terlebih dahulu mengosongkan node, lalu menerapkan profil penyesuaian. Akibatnya, node dapat melaporkan status
NotReady
selama penyesuaian performa. Sebaiknya gunakan strategi update berkelanjutan (spec.updateStrategy.type: rolling
), bukan update batch, untuk meminimalkan ketidaktersediaan beban kerja.Memerlukan mulai ulang: Agar perubahan penyesuaian node diterapkan, Operator Penyesuaian Performa akan memulai ulang node setelah menerapkan profil penyesuaian.
Menginstal Operator Penyesuaian Performa
Operator Penyesuaian Performa terutama terdiri dari dua pengontrol (Deployment dan DaemonSet)
yang berinteraksi satu sama lain untuk menyesuaikan node berdasarkan setelan profil Anda.
Operator Penyesuaian Performa tidak diinstal dengan Google Distributed Cloud, secara default. Anda mendownload
manifes Performance Tuning Operator dari Cloud Storage dan menggunakan kubectl apply
untuk
membuat resource Performance Tuning Operator di cluster Anda.
Untuk mengaktifkan penyesuaian performa dengan nilai default untuk cluster Anda:
Buat direktori
performance-tuning
di workstation admin Anda.Dari direktori
performance-tuning
, download paket Performance Tuning Operator terbaru dari bucket rilis Cloud Storage:gcloud storage cp gs://anthos-baremetal-release/node-performance-tuning/0.1.0-gke.47 . --recursive
File yang didownload mencakup manifes untuk Deployment
performance-tuning-operator
dan DaemonSetnodeconfig-controller-manager
. Manifes untuk fungsi terkait, seperti kontrol akses berbasis peran (RBAC) dan kontrol akses masuk dinamis, juga disertakan.Sebagai pengguna root, terapkan semua manifes Operator Penyesuaian Performa secara rekursif ke cluster pengguna (atau campuran) Anda:
kubectl apply -f performance-tuning --recursive –-kubeconfig USER_KUBECONFIG
Setelah Deployment dan DaemonSet dibuat dan berjalan, satu-satunya interaksi Anda adalah mengedit dan menerapkan manifes
PerformanceTuningProfile
.
Meninjau persyaratan resource untuk workload Anda
Sebelum dapat menyesuaikan node, Anda perlu memahami persyaratan resource komputasi dan memori beban kerja Anda. Jika node pekerja memiliki resource yang memadai, node dapat disesuaikan untuk menyediakan memori yang terjamin (standar dan hugepage) untuk workload Anda di class Kualitas Layanan (QoS) yang terjamin.
Kubernetes menetapkan class QoS ke setiap Pod, berdasarkan batasan resource yang Anda tentukan untuk penampung terkait. Kemudian, Kubernetes menggunakan class QoS untuk menentukan cara menjadwalkan Pod dan penampung serta mengalokasikan resource ke workload Anda. Untuk memanfaatkan sepenuhnya Penyesuaian node untuk workload, workload Anda harus memiliki permintaan atau setelan batas resource CPU atau memori.
Agar ditetapkan ke kelas QoS yang dijamin, Pod Anda harus memenuhi persyaratan berikut:
- Untuk setiap Penampung di Pod:
- Tentukan nilai untuk permintaan resource memori
(
spec.containers[].resources.requests.memory
) dan batas (spec.containers[].resources.limits.memory
). - Nilai batas memori harus sama dengan nilai permintaan memori.
- Tentukan nilai untuk permintaan resource CPU
(
spec.containers[].resources.requests.cpu
) dan batas (spec.containers[].resources.limits.cpu
). - Nilai batas CPU harus sama dengan nilai permintaan CPU.
- Tentukan nilai untuk permintaan resource memori
(
Cuplikan spesifikasi Pod berikut menunjukkan setelan resource CPU yang memenuhi persyaratan class QoS terjamin:
spec:
containers:
- name: sample-app
image: images.my-company.example/app:v4
resources:
requests:
memory: "128Mi"
cpu: "2"
limits:
memory: "128Mi"
cpu: "2"
...
Saat Anda mengambil detail pod dengan kubectl get pods
, bagian status
harus menyertakan class QoS yang ditetapkan seperti yang ditunjukkan dalam contoh berikut:
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: "2023-09-22T21:05:23Z"
generateName: my-deployment-6fdd69987d-
labels:
app: metrics
department: sales
pod-template-hash: 6fdd69987d
name: my-deployment-6fdd69987d-7kv42
namespace: default
...
spec:
containers:
...
status:
conditions:
- lastProbeTime: null
lastTransitionTime: "2023-09-22T21:05:23Z"
status: "True"
type: Initialized
...
qosClass: BestEffort
startTime: "2023-09-22T21:05:23Z"
Untuk mengetahui informasi selengkapnya tentang class QoS, lihat Class Kualitas Layanan Pod dalam dokumentasi Kubernetes. Untuk petunjuk cara mengonfigurasi Pod dan penampung agar diberi kelas QoS, lihat Mengonfigurasi Kualitas Layanan untuk Pod
Persyaratan CPU
Saat menyesuaikan node, Anda dapat menentukan serangkaian core CPU yang dicadangkan
(spec.cpu.reservedCPUs
) untuk menjalankan daemon sistem Kubernetes seperti kubelet
dan runtime container. Kumpulan CPU yang dicadangkan yang sama ini juga menjalankan daemon sistem operasi, seperti sshd
dan udev
. Sisa core CPU di area tersebut
dialokasikan sebagai terisolasi. CPU yang terisolasi ditujukan untuk aplikasi terikat CPU, yang memerlukan waktu CPU khusus tanpa gangguan dari aplikasi
lain atau gangguan dari jaringan atau perangkat lain.
Untuk menjadwalkan Pod di CPU terisolasi node pekerja:
Konfigurasikan Pod untuk kualitas layanan terjamin (QoS).
Persyaratan dan batas CPU harus ditentukan dalam bilangan bulat. Jika Anda menentukan resource CPU sebagian dalam spesifikasi Pod, seperti
cpu: 0.5
ataucpu: 250m
(250 millicore), penjadwalan tidak dapat dijamin.
Persyaratan memori
Saat menyesuaikan node dengan Performance Tuning Operator, Anda dapat membuat hugepage dan mengaitkannya dengan node non-uniform memory access (NUMA) di mesin. Berdasarkan setelan Pod dan Node, Pod dapat dijadwalkan dengan afinitas node NUMA.
Membuat profil penyesuaian performa
Setelah menginstal Operator Penyesuaian Performa, Anda hanya berinteraksi dengan cluster yang menjalankan
workload Anda. Anda membuat resource kustom PerformanceTuningProfile
langsung di cluster pengguna atau cluster campuran, bukan di cluster admin. Setiap
resource PerformanceTuningProfile
berisi kumpulan parameter yang menentukan
konfigurasi performa yang diterapkan ke node.
nodeSelector
dalam resource menentukan node tempat
profil penyesuaian diterapkan. Untuk menerapkan profil ke node, Anda menempatkan
label key-value pair yang sesuai pada node. Profil penyesuaian diterapkan ke node yang memiliki semua label yang ditentukan di kolom nodeSelector
.
Anda dapat membuat beberapa resource PerformanceTuningProfile
dalam cluster. Jika
lebih dari satu profil cocok dengan node tertentu, kondisi error akan ditetapkan di
status
resource kustom PerformanceTuningProfile
. Untuk informasi
selengkapnya tentang bagian status
, lihat Memeriksa status.
Tetapkan namespace untuk resource kustom PerformanceTuningProfile
Anda ke
kube-system
.
Untuk menyesuaikan satu atau beberapa node pekerja:
Edit manifes
PerformanceTuningProfile
.Untuk informasi tentang setiap kolom dalam manifes dan contoh manifes, lihat referensi resource
PerformanceTuningProfile
.(Opsional) Untuk Node pekerja tempat Anda menerapkan profil, tambahkan label agar cocok dengan pasangan nilai kunci
spec.nodeSelector
.Jika tidak ada pasangan nilai kunci
spec.nodeSelector
yang ditentukan dalam resource kustomPerformanceTuningProfile
, profil akan diterapkan ke semua node pekerja.Terapkan manifes ke cluster Anda.
kubectl apply -f PROFILE_MANIFEST --kubeconfig KUBECONFIG
Ganti kode berikut:
PROFILE_MANIFEST
: jalur file manifes untuk resource kustomPerformanceTuningProfile
.KUBECONFIG
: jalur file kubeconfig cluster.
Menghapus profil penyesuaian
Untuk mereset node ke status aslinya yang tidak disetel:
Hapus resource kustom
PerformanceTuningProfile
dari cluster.Perbarui atau hapus label pada node agar tidak dipilih lagi oleh profil penyesuaian.
Jika Anda memiliki beberapa profil penyesuaian yang terkait dengan node, ulangi langkah-langkah sebelumnya, sesuai kebutuhan.
Menjeda profil penyesuaian
Jika perlu melakukan pemeliharaan pada cluster, Anda dapat menjeda penyesuaian untuk sementara dengan mengedit resource kustom PerformanceTuningProfile
. Sebaiknya
jeda penyesuaian sebelum Anda melakukan operasi cluster penting, seperti upgrade
cluster.
Penerapan profil yang tidak berhasil adalah kasus lain saat Anda dapat menjeda penyesuaian. Jika proses penyesuaian tidak berhasil, pengontrol dapat terus mencoba menyesuaikan node, yang dapat menyebabkan node dimulai ulang berulang kali. Jika Anda mengamati status node yang beralih antara status siap dan tidak siap, jeda penyesuaian agar Anda dapat memulihkan dari status rusak.
Untuk menjeda penyesuaian:
Edit manifes resource kustom
PerformanceTuningProfile
untuk menetapkanspec.paused
ketrue
.Gunakan
kubectl apply
untuk memperbarui resource.
Saat penyesuaian performa dijeda, pengontrol Operator Penyesuaian Performa akan menghentikan semua operasinya. Jeda mencegah risiko operasi pengontrol Performance Tuning Operator bertentangan dengan operasi pengontrol Google Distributed Cloud.
Referensi resource PerformanceTuningProfile
Bagian ini menjelaskan setiap kolom dalam resource kustom
PerformanceTuningProfile
. Resource ini digunakan untuk membuat profil penyesuaian untuk satu atau beberapa node cluster Anda. Semua kolom dalam resource dapat diubah setelah pembuatan profil. Profil harus berada dalam namespace kube-system
.
Contoh manifes profil numa
berikut untuk node dengan 8 core CPU
menentukan alokasi resource berikut:
4 core CPU (
0-3
) dicadangkan untuk overhead sistem Kubernetes.4 core CPU (
4-7
) disisihkan hanya untuk beban kerja.Memori node dibagi menjadi halaman 2‑MiB secara default, bukan halaman 4‑Ki standar.
10 halaman memori berukuran 1 GiB disisihkan untuk digunakan oleh node NUMA 0.
5 halaman memori berukuran 2 MiB disisihkan untuk digunakan oleh node NUMA 1.
Pengelola Topologi menggunakan kebijakan terbaik untuk menjadwalkan beban kerja.
apiVersion: anthos.gke.io/v1alpha1
kind: PerformanceTuningProfile
metadata:
name: numa
namespace: kube-system
spec:
cpu:
isolatedCPUs: 4-7
reservedCPUs: 0-3
defaultHugepagesSize: 2M
nodeSelector:
app: database
node-role.kubernetes.io/worker: ""
pages:
- count: 10
numaNode: 0
size: 1G
- count: 5
numaNode: 1
size: 2M
topologyManagerPolicy: best-effort
Anda dapat mengambil definisi resource kustom PerformanceTuningProfile
terkait
dari grup anthos.gke.io
di cluster. Definisi resource kustom
diinstal setelah anotasi fitur pratinjau ditambahkan ke
resource cluster yang dikelola sendiri.
Konfigurasi CPU
Properti | Deskripsi |
---|---|
cpu.reservedCPUs |
Wajib. Dapat berubah. String. Kolom ini menentukan kumpulan core CPU yang akan
dicadangkan untuk daemon sistem Kubernetes, seperti kubelet, runtime
container, dan pendeteksi masalah node. Core CPU ini juga digunakan untuk
daemon sistem sistem operasi (OS), seperti sshd dan
udev .
Kolom |
cpu.isolatedCPUs |
Opsional. Dapat berubah. String. Kolom cpu.isolatedCPUs
menentukan kumpulan CPU yang digunakan secara eksklusif untuk aplikasi
yang sensitif terhadap performa. Pengelola CPU menjadwalkan penampung hanya di CPU yang tidak direservasi, sesuai dengan class Kualitas Layanan (QoS) Kubernetes.
Untuk memastikan workload berjalan di CPU yang terisolasi,
konfigurasi Pod dengan class QoS terjamin dan
tetapkan resource CPU ke Pod atau Container.
Untuk penjadwalan Pod yang terjamin, Anda harus menentukan unit CPU bilangan bulat, bukan
resource CPU parsial (cpu: "0.5" ).
apiVersion: v1 kind: Pod ... spec: containers: ... resources: limits: cpu: "1" requests: cpu: "1" ... Memaksimalkan CPU terisolasi untuk workload memberikan manfaat performa
terbaik. Kolom ini menggunakan daftar angka CPU atau rentang angka CPU.
Pastikan daftar CPU tidak tumpang-tindih dengan daftar yang ditentukan dengan
|
cpu.balanceIsolated |
Opsional. Dapat berubah. Boolean. Default: true . Kolom ini
menentukan apakah set CPU Terisolasi memenuhi syarat untuk load balancing
otomatis pada workload di seluruh CPU atau tidak. Saat Anda menetapkan kolom ini ke
false , beban kerja Anda harus menetapkan setiap thread secara eksplisit
ke CPU tertentu untuk mendistribusikan beban di seluruh CPU. Dengan penetapan CPU eksplisit, Anda mendapatkan performa yang paling dapat diprediksi untuk workload terjamin, tetapi hal ini akan menambah kompleksitas pada workload Anda. |
cpu.globallyEnableIRQLoadBalancing |
Wajib. Dapat berubah. Boolean. Default: true . Kolom ini
menentukan apakah akan mengaktifkan atau tidak load balancing permintaan interupsi (IRQ)
untuk set CPU yang terisolasi. |
Konfigurasi memori
Properti | Deskripsi |
---|---|
defaultHugePageSize |
Opsional. Dapat berubah. Enumerasi: 1G atau 2M .
Kolom ini menentukan ukuran hugepage default dalam parameter booting kernel.
Hugepage dialokasikan pada waktu booting, sebelum memori menjadi terfragmentasi.
Perlu diperhatikan bahwa menetapkan ukuran default hugepages ke 1G akan menghapus semua folder terkait 2M dari node. Ukuran hugepage default sebesar
1 G mencegah Anda mengonfigurasi hugepage 2 M di node.
|
pages |
Opsional. Dapat berubah. Bilangan bulat. Kolom ini menentukan jumlah hugepage yang akan dibuat pada waktu booting. Kolom ini menerima array halaman. Periksa memori yang tersedia untuk node Anda sebelum menentukan hugepage. Jangan meminta hugepage lebih dari yang diperlukan dan jangan mencadangkan semua memori untuk hugepage. Workload Anda juga memerlukan memori standar. |
Pemilihan Node
Properti | Deskripsi |
---|---|
nodeSelector |
Wajib. Dapat berubah. Kolom ini selalu memerlukan label node pekerja Kubernetes, node-role.kubernetes.io/worker:"" , yang memastikan bahwa penyesuaian performa hanya dilakukan pada node pekerja. Kolom ini menggunakan
label node opsional sebagai pasangan nilai kunci. Label pasangan nilai kunci
digunakan untuk memilih node pekerja tertentu dengan label yang cocok. Jika label nodeSelector cocok dengan label di node pekerja, profil performa akan diterapkan ke node tersebut. Jika Anda tidak menentukan label nilai kunci di profil, label tersebut akan diterapkan ke semua node pekerja di cluster.
Misalnya, ... spec: nodeSelector: app: database node-role.kubernetes.io/worker: "" ... |
Konfigurasi Kubelet
Properti | Deskripsi |
---|---|
topologyManagerPolicy |
Opsional. Dapat berubah. Enumerasi: none , best-effort ,
restricted , atau single-numa-node . Default: best-effort .
Kolom ini menentukan kebijakan Pengelola Topologi Kubernetes yang digunakan untuk mengalokasikan resource untuk workload Anda, berdasarkan class kualitas layanan (QoS) yang ditetapkan. Untuk informasi selengkapnya tentang cara menetapkan class QoS, lihat Mengonfigurasi Kualitas Layanan untuk Pod.
|
Operasi profil
Properti | Deskripsi |
---|---|
paused |
Opsional. Dapat berubah. Boolean. Tetapkan paused ke
true untuk sementara mencegah pengontrol DaemonSet
menyesuaikan node yang dipilih. |
updateStrategy |
Opsional. Dapat berubah. Menentukan strategi untuk menerapkan perubahan konfigurasi penyesuaian ke node yang dipilih. |
updateStrategy.rollingUpdateMaxUnavailalble |
Opsional. Dapat berubah. Bilangan bulat. Default: 1 . Menentukan
jumlah maksimum node yang dapat disesuaikan secara bersamaan. Kolom ini
hanya berlaku jika type ditetapkan ke rolling . |
updateStrategy.type |
Opsional. Dapat berubah. Enumerasi: batch atau rolling .
Default: rolling . Menentukan cara menerapkan update profil
ke node yang dipilih. Jika Anda ingin menerapkan pembaruan ke semua node yang dipilih
secara bersamaan, tetapkan type ke batch . Secara default, update diluncurkan secara berurutan ke setiap node, satu per satu. |
Periksa status
Setelah resource kustom PerformanceTuningProfile
dibuat atau diperbarui, pengontrol akan menyesuaikan node yang dipilih berdasarkan konfigurasi yang disediakan dalam resource. Untuk memeriksa status PerformanceTuningProfile
, kita mengekspos
kolom berikut di Status
:
Properti | Deskripsi |
---|---|
conditions |
Kondisi mewakili pengamatan terbaru yang tersedia tentang status resource profil saat ini. |
conditions.lastTransitionTime |
Selalu ditampilkan. String (dalam format tanggal-waktu). Terakhir kali kondisi bertransisi dari satu status ke status lainnya. Waktu ini biasanya menunjukkan kapan kondisi yang mendasarinya berubah. Jika waktu tersebut tidak diketahui, waktu tersebut akan menunjukkan kapan kolom API berubah. |
conditions.message |
Opsional. String. Pesan yang dapat dibaca manusia yang menunjukkan detail tentang transisi. Kolom ini mungkin kosong. |
conditions.observedGeneration |
Opsional. Bilangan bulat. Jika ditetapkan, kolom ini mewakili metadata.generation
yang menjadi dasar penetapan kondisi. Misalnya, jika metadata.generation
adalah 12 , tetapi status.condition[x].observedGeneration
adalah 9 , kondisi tersebut sudah tidak berlaku terkait status
instance saat ini. |
conditions.reason |
Wajib. String. Alasan transisi kondisi terakhir. |
conditions.status |
Wajib. Status kondisi: True , False , atau
Unknown . |
conditions.type |
Wajib. Jenis adalah jenis kondisi: Stalled atau
Reconciling . |
readyNodes |
Jumlah node tempat profil penyesuaian berhasil diterapkan. |
reconcilingNodes |
Jumlah node yang dipilih (atau sebelumnya dipilih) yang sedang
dalam proses rekonsiliasi dengan profil penyesuaian terbaru oleh
DaemonSet nodeconfig-controller-manager . |
selectedNodes |
Jumlah catatan yang telah dipilih. Artinya, jumlah node yang cocok dengan pemilih node untuk resource kustom PerformanceTuningProfile ini. |