Artikel ini membawakan anda pengetahuan yang berkaitan tentang Redis Kelewatan Redis yang berlebihan boleh menyebabkan pelbagai masalah Mari kita menganalisis cara untuk menentukan sama ada Redis mempunyai masalah prestasi dan Penyelesaian, harap ia membantu semua orang.
Pembelajaran yang disyorkan: Tutorial Redis
Redis biasanya merupakan komponen penting dalam sistem perniagaan kami, seperti: caching, log masuk akaun Maklumat, kedudukan, dsb.
Apabila kelewatan permintaan Redis meningkat, ia boleh menyebabkan "avalanche" sistem perniagaan.
Saya bekerja untuk syarikat Internet jenis pembuat jodoh tunggal Semasa Double Eleven, saya melancarkan kempen untuk memberi hadiah kepada teman wanita saya apabila saya membuat pesanan.
Siapa sangka selepas jam 12 pagi, jumlah pengguna meningkat dengan mendadak, dan berlaku gangguan teknikal yang menghalang pengguna untuk membuat tempahan Pada masa itu, kebakaran lama berlaku!
Selepas mencari, saya menjumpai laporan Redis Could not get a resource from the pool
.
Tidak boleh mendapatkan sumber sambungan dan bilangan sambungan kepada satu Redis dalam gugusan adalah sangat tinggi.
Sebilangan besar trafik kehilangan respons cache Redis dan memukul MySQL secara langsung, dan akhirnya pangkalan data telah turun...
Jadi pelbagai perubahan telah dibuat kepada bilangan maksimum sambungan dan bilangan sambungan menunggu, walaupun mesej ralat telah dilaporkan Kekerapan telah berkurangan, tetapi ralat masih berterusan.
Kemudian, selepas ujian luar talian, didapati bahawa data aksara yang disimpan dalam Redis adalah sangat besar, dan data dikembalikan dalam purata 1s.
Boleh didapati apabila kelewatan Redis terlalu tinggi, ia akan menyebabkan pelbagai masalah.
Hari ini, mari analisa cara untuk menentukan sama ada Redis mempunyai masalah prestasi dan penyelesaian.
Lengah maksimum ialah masa daripada klien mengeluarkan arahan kepada klien menerima respons kepada arahan Dalam keadaan biasa, masa pemprosesan Redis adalah sangat singkat, pada tahap mikrosaat.
Apabila prestasi Redis turun naik, contohnya, ia mencapai beberapa saat hingga lebih daripada sepuluh saat, jelas sekali kita boleh membuat kesimpulan bahawa prestasi Redis telah menjadi perlahan.
Sesetengah konfigurasi perkakasan agak tinggi Apabila kelewatan adalah 0.6ms, kami mungkin menganggapnya perlahan. Jika perkakasan agak lemah, ia mungkin mengambil masa 3 ms sebelum kami fikir ada masalah.
Jadi bagaimana kita menentukan sama ada Redis benar-benar lambat?
Jadi, kita perlu mengukur prestasi garis dasar Redis bagi persekitaran semasa, iaitu prestasi asas sistem di bawah tekanan rendah dan tiada gangguan.
Apabila anda mendapati bahawa kependaman masa jalan Redis adalah lebih daripada 2 kali ganda prestasi garis dasar, anda boleh menentukan bahawa prestasi Redis semakin perlahan.
Pengukuran garis dasar kependaman
Arahan redis-cli menyediakan pilihan –intrinsik-latency untuk memantau dan mengira kependaman maksimum semasa tempoh ujian (diukur dalam milisaat), kelewatan ini boleh digunakan sebagai prestasi garis dasar Redis.
redis-cli --latency -h `host` -p `port`
Sebagai contoh, laksanakan arahan berikut:
redis-cli --intrinsic-latency 100 Max latency so far: 4 microseconds. Max latency so far: 18 microseconds. Max latency so far: 41 microseconds. Max latency so far: 57 microseconds. Max latency so far: 78 microseconds. Max latency so far: 170 microseconds. Max latency so far: 342 microseconds. Max latency so far: 3079 microseconds. 45026981 total runs (avg latency: 2.2209 microseconds / 2220.89 nanoseconds per run). Worst run took 1386x longer than the average latency.
Nota: Parameter 100 ialah bilangan saat ujian akan dilaksanakan. Semakin lama kami menjalankan ujian, semakin besar kemungkinan kami menemui lonjakan latensi.
Biasanya berjalan selama 100 saat biasanya sesuai, yang cukup untuk mengesan masalah kependaman Sudah tentu, kita boleh memilih untuk menjalankan beberapa kali pada masa yang berbeza untuk mengelakkan ralat.
Latensi kependaman maksimum ialah 3079 mikrosaat, jadi prestasi garis dasar ialah 3079 (3 milisaat) mikrosaat.
Perlu diingatkan bahawa kita perlu berjalan pada pelayan Redis, bukan klien. Dengan cara ini, impak rangkaian pada prestasi garis dasar boleh dielakkan.
Anda boleh menyambung ke pelayan melalui -h host -p port
Jika anda ingin memantau kesan rangkaian pada prestasi Redis, anda boleh menggunakan Iperf untuk mengukur kelewatan rangkaian daripada klien ke pelayan.
Jika rangkaian terlewat beberapa ratus milisaat, ini bermakna program trafik tinggi yang lain mungkin berjalan pada rangkaian, menyebabkan kesesakan rangkaian Anda perlu mencari operasi dan penyelenggaraan untuk menyelaraskan pengagihan trafik rangkaian.
Bagaimana untuk menilai sama ada ia adalah arahan yang perlahan?
Lihat sama ada kerumitan operasi ialah O(N). Dokumentasi rasmi memperkenalkan kerumitan setiap arahan Gunakan perintah O(1) dan O(log N) sebanyak mungkin.
Kerumitan yang terlibat dalam operasi set biasanya O(N), seperti pertanyaan set penuh HGETALL, SMEMBERS dan operasi pengagregatan set: SORT, LREM, SUNION, dsb.
Adakah terdapat sebarang data pemantauan yang boleh diperhatikan? Saya tidak menulis kod saya tidak tahu sama ada sesiapa telah menggunakan arahan yang perlahan.
Terdapat dua cara untuk menyemak:
Gunakan fungsi log perlahan Redis untuk mengesan arahan perlahan; >alat pemantau kependaman.
Selain itu, anda boleh menggunakan diri anda (atas, htop, prstat, dll.) untuk menyemak penggunaan CPU proses utama Redis dengan cepat. Jika penggunaan CPU tinggi tetapi trafik rendah, ia biasanya menunjukkan bahawa arahan perlahan sedang digunakan.
慢日志功能
Redis 中的 slowlog 命令可以让我们快速定位到那些超出指定执行时间的慢命令,默认情况下命令若是执行时间超过 10ms 就会被记录到日志。
slowlog 只会记录其命令执行的时间,不包含 io 往返操作,也不记录单由网络延迟引起的响应慢。
我们可以根据基线性能来自定义慢命令的标准(配置成基线性能最大延迟的 2 倍),调整触发记录慢命令的阈值。
可以在 redis-cli 中输入以下命令配置记录 6 毫秒以上的指令:
redis-cli CONFIG SET slowlog-log-slower-than 6000
也可以在 Redis.config 配置文件中设置,以微秒为单位。
想要查看所有执行时间比较慢的命令,可以通过使用 Redis-cli 工具,输入 slowlog get 命令查看,返回结果的第三个字段以微秒位单位显示命令的执行时间。
假如只需要查看最后 2 个慢命令,输入 slowlog get 2 即可。
示例:获取最近2个慢查询命令
127.0.0.1:6381> SLOWLOG get 2 1) 1) (integer) 6 2) (integer) 1458734263 3) (integer) 74372 4) 1) "hgetall" 2) "max.dsp.blacklist" 2) 1) (integer) 5 2) (integer) 1458734258 3) (integer) 5411075 4) 1) "keys" 2) "max.dsp.blacklist"
以第一个 HGET 命令为例分析,每个 slowlog 实体共 4 个字段:
字段 1:1 个整数,表示这个 slowlog 出现的序号,server 启动后递增,当前为 6。
字段 2:表示查询执行时的 Unix 时间戳。
字段 3:表示查询执行微秒数,当前是 74372 微秒,约 74ms。
字段 4: 表示查询的命令和参数,如果参数很多或很大,只会显示部分参数个数。当前命令是hgetall max.dsp.blacklist。
Latency Monitoring
Redis 在 2.8.13 版本引入了 Latency Monitoring 功能,用于以秒为粒度监控各种事件的发生频率。
启用延迟监视器的第一步是设置延迟阈值(单位毫秒)。只有超过该阈值的时间才会被记录,比如我们根据基线性能(3ms)的 3 倍设置阈值为 9 ms。
可以用 redis-cli 设置也可以在 Redis.config 中设置;
CONFIG SET latency-monitor-threshold 9
工具记录的相关事件的详情可查看官方文档:https://redis.io/topics/latency-monitor
如获取最近的 latency
127.0.0.1:6379> debug sleep 2 OK (2.00s) 127.0.0.1:6379> latency latest 1) 1) "command" 2) (integer) 1645330616 3) (integer) 2003 4) (integer) 2003
事件的名称;
事件发生的最新延迟的 Unix 时间戳;
毫秒为单位的时间延迟;
该事件的最大延迟。
Redis 的数据读写由单线程执行,如果主线程执行的操作时间太长,就会导致主线程阻塞。
一起分析下都有哪些操作会阻塞主线程,我们又该如何解决?
网络通信导致的延迟
客户端使用 TCP/IP 连接或 Unix 域连接连接到 Redis。1 Gbit/s 网络的典型延迟约为 200 us。
redis 客户端执行一条命令分 4 个过程:
发送命令-〉 命令排队 -〉 命令执行-〉 返回结果
这个过程称为 Round trip time(简称 RTT, 往返时间),mget mset 有效节约了 RTT,但大部分命令(如 hgetall,并没有 mhgetall)不支持批量操作,需要消耗 N 次 RTT ,这个时候需要 pipeline 来解决这个问题。
Redis pipeline 将多个命令连接在一起来减少网络响应往返次数。
redis-pipeline
慢指令导致的延迟
根据上文的慢指令监控查询文档,查询到慢查询指令。可以通过以下两种方式解决:
比如在 Cluster 集群中,将聚合运算等 O(N) 操作运行在 slave 上,或者在客户端完成。
使用高效的命令代替。使用增量迭代的方式,避免一次查询大量数据,具体请查看SCAN、SSCAN、HSCAN和ZSCAN命令。
除此之外,生产中禁用KEYS 命令,它只适用于调试。因为它会遍历所有的键值对,所以操作延时高。
Fork 生成 RDB 导致的延迟
生成 RDB 快照,Redis 必须 fork 后台进程。fork 操作(在主线程中运行)本身会导致延迟。
Redis 使用操作系统的多进程写时复制技术 COW(Copy On Write) 来实现快照持久化,减少内存占用。
写时复制技术保证快照期间数据可修改
但 fork 会涉及到复制大量链接对象,一个 24 GB 的大型 Redis 实例需要 24 GB / 4 kB * 8 = 48 MB 的页表。
执行 bgsave 时,这将涉及分配和复制 48 MB 内存。
此外,从库加载 RDB 期间无法提供读写服务,所以主库的数据量大小控制在 2~4G 左右,让从库快速的加载完成。
内存大页(transparent huge pages)
常规的内存页是按照 4 KB 来分配,Linux 内核从 2.6.38 开始支持内存大页机制,该机制支持 2MB 大小的内存页分配。
Redis 使用了 fork 生成 RDB 做持久化提供了数据可靠性保证。
当生成 RDB 快照的过程中,Redis 采用**写时复制**技术使得主线程依然可以接收客户端的写请求。
也就是当数据被修改的时候,Redis 会复制一份这个数据,再进行修改。
采用了内存大页,生成 RDB 期间,即使客户端修改的数据只有 50B 的数据,Redis 需要复制 2MB 的大页。当写的指令比较多的时候就会导致大量的拷贝,导致性能变慢。
使用以下指令禁用 Linux 内存大页即可:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
swap:操作系统分页
当物理内存(内存条)不够用的时候,将部分内存上的数据交换到 swap 空间上,以便让系统不会因内存不够用而导致 oom 或者更致命的情况出现。
当某进程向 OS 请求内存发现不足时,OS 会把内存中暂时不用的数据交换出去,放在 SWAP 分区中,这个过程称为 SWAP OUT。
当某进程又需要这些数据且 OS 发现还有空闲物理内存时,又会把 SWAP 分区中的数据交换回物理内存中,这个过程称为 SWAP IN。
内存 swap 是操作系统里将内存数据在内存和磁盘间来回换入和换出的机制,涉及到磁盘的读写。
触发 swap 的情况有哪些呢?
对于 Redis 而言,有两种常见的情况:
Redis 使用了比可用内存更多的内存;
与 Redis 在同一机器运行的其他进程在执行大量的文件读写 I/O 操作(包括生成大文件的 RDB 文件和 AOF 后台线程),文件读写占用内存,导致 Redis 获得的内存减少,触发了 swap。
我要如何排查是否因为 swap 导致的性能变慢呢?
Linux 提供了很好的工具来排查这个问题,所以当怀疑由于交换导致的延迟时,只需按照以下步骤排查。
获取 Redis 实例 pid
$ redis-cli info | grep process_id process_id:13160
进入此进程的 /proc 文件系统目录:
cd /proc/13160
在这里有一个 smaps 的文件,该文件描述了 Redis 进程的内存布局,运行以下指令,用 grep 查找所有文件中的 Swap 字段。
$ cat smaps | egrep '^(Swap|Size)' Size: 316 kB Swap: 0 kB Size: 4 kB Swap: 0 kB Size: 8 kB Swap: 0 kB Size: 40 kB Swap: 0 kB Size: 132 kB Swap: 0 kB Size: 720896 kB Swap: 12 kB
每行 Size 表示 Redis 实例所用的一块内存大小,和 Size 下方的 Swap 对应这块 Size 大小的内存区域有多少数据已经被换出到磁盘上了。
如果 Size == Swap 则说明数据被完全换出了。
可以看到有一个 720896 kB 的内存大小有 12 kb 被换出到了磁盘上(仅交换了 12 kB),这就没什么问题。
Redis 本身会使用很多大小不一的内存块,所以,你可以看到有很多 Size 行,有的很小,就是 4KB,而有的很大,例如 720896KB。不同内存块被换出到磁盘上的大小也不一样。
敲重点了
如果 Swap 一切都是 0 kb,或者零星的 4k ,那么一切正常。
当出现百 MB,甚至 GB 级别的 swap 大小时,就表明,此时,Redis 实例的内存压力很大,很有可能会变慢。
解决方案
增加机器内存;
Jalankan Redis pada mesin yang berasingan untuk mengelakkan proses yang memerlukan jumlah memori yang besar pada mesin yang sama untuk memenuhi keperluan memori Redis
Tingkatkan bilangan gugusan Kluster untuk berkongsi jumlah data dan kurangkan jumlah setiap Memori yang diperlukan oleh contoh.
Kelewatan yang disebabkan oleh AOF dan cakera I/O
Untuk memastikan kebolehpercayaan data, Redis menggunakan syot kilat AOF dan RDB untuk mencapai pemulihan pantas dan perubahan ketahanan.
AOF boleh dikonfigurasikan untuk melaksanakan tulis atau fsync pada cakera dalam tiga cara berbeza menggunakan konfigurasi appendfsync (tetapan ini boleh diubah suai pada masa jalan menggunakan arahan CONFIG SET, seperti: redis-cli CONFIG SET appendfsync no ).
tidak: Redis tidak melakukan fsync Satu-satunya kelewatan datang daripada panggilan tulis hanya perlu menulis rekod log ke penimbal kernel sebelum kembali.
setiap saat: Redis melaksanakan fsync sekali sesaat. Gunakan sub-benang latar belakang untuk menyelesaikan operasi fsync secara tak segerak. Paling banyak 1s data akan hilang.
sentiasa: fsync akan dilakukan pada setiap operasi tulis dan kemudian balas kepada klien dengan kod OK (sebenarnya Redis akan cuba mengagregatkan banyak arahan yang dilaksanakan serentak ke dalam satu fsync), tidak Data hilang. Dalam mod ini, prestasi biasanya sangat perlahan, dan sangat disyorkan untuk menggunakan cakera pantas dan pelaksanaan sistem fail yang boleh melakukan fsync dalam masa yang singkat.
Kami biasanya menggunakan Redis untuk menyimpan data adalah berniat jahat dan tidak memerlukan kebolehpercayaan data yang tinggi.
Selain itu, untuk mengelakkan fail AOF terlalu besar, Redis akan menulis semula AOF dan menjana fail AOF yang dikurangkan.
Anda boleh menetapkan item konfigurasi no-appendfsync-on-rewrite kepada ya, yang bermaksud bahawa operasi fsync tidak akan dilakukan apabila AOF ditulis semula.
Dalam erti kata lain, selepas kejadian Redis menulis arahan tulis ke memori, ia kembali terus tanpa memanggil utas latar belakang untuk melaksanakan operasi fsync.
tamat tempoh Hapuskan data tamat tempoh
Redis mempunyai dua cara untuk menghapuskan data tamat tempoh:
malas Pemadaman: Apabila menerima permintaan, didapati bahawa kunci telah tamat tempoh, dan kemudian pemadaman dilakukan;
Algoritma untuk pemadaman berjadual adalah seperti berikut:
ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP ditetapkan kepada 20 secara lalai dan dilaksanakan 10 kali sesaat Tidak menjadi masalah besar untuk memadamkan 200 kekunci.
Jika item kedua dicetuskan, ia akan menyebabkan Redis memadamkan data tamat tempoh secara konsisten untuk mengosongkan memori. Dan pemadaman menyekat.
Apakah keadaan yang mencetuskan?Iaitu, sebilangan besar kekunci menetapkan parameter masa yang sama. Pada saat yang sama, sejumlah besar kunci tamat tempoh dan perlu dipadamkan beberapa kali untuk mengurangkannya kepada kurang daripada 25%.
Ringkasnya: sebilangan besar kunci tamat tempoh pada masa yang sama boleh menyebabkan turun naik prestasi.
Penyelesaian
Jika sekumpulan kunci tamat tempoh pada masa yang sama, anda boleh menambah nilai tertentu pada parameter masa tamat tempoh EXPIREAT dan EXPIRE Nombor rawak dalam julat saiz, ini bukan sahaja memastikan bahawa kunci dipadamkan dalam julat masa yang berdekatan, tetapi juga mengelakkan tekanan yang disebabkan oleh tamat tempoh serentak. bigkey
Biasanya kami memanggil Key yang mengandungi data yang besar atau bilangan ahli yang besar atau senarai sebagai Key yang besar contoh praktikal akan digunakan untuk menerangkan ciri-ciri Kunci besar: Kekunci jenis STRING dengan nilai 5MB (data terlalu besar)
Memori nod tertentu dalam Kluster Redis jauh melebihi nod lain, tetapi kerana kebutiran minimum pemindahan data dalam Kluster Redis ialah Kunci, memori pada nod tidak boleh diseimbangkan; >
Pisah kunci besar
Sebagai contoh, bahagikan Kunci HASH yang mengandungi puluhan ribu ahli kepada Berbilang Kunci HASH, dan pastikan bilangan ahli setiap Kunci berada dalam julat yang munasabah Dalam struktur Kluster Redis, pemisahan Kekunci besar boleh memainkan peranan penting dalam keseimbangan memori antara nod. Pembersihan asynchronous kunci besarRedis telah menyediakan perintah UNLINK sejak 4.0, yang boleh membersihkan Key yang masuk secara perlahan dan beransur-ansur tanpa menyekat Melalui UNLINK, anda boleh memadam dengan selamat ia Kunci Besar atau Kunci Tambahan Besar. Ringkasan
Senarai semak berikut akan membantu anda menyelesaikan masalah dengan cekap apabila prestasi Redis menjadi perlahan. Dapatkan prestasi asas semasa Redis; Dayakan pemantauan arahan perlahan dan cari masalah yang disebabkan oleh arahan perlahan; >Kawal saiz data contoh kepada 2-4GB untuk mengelak daripada menyekat replikasi induk-hamba dengan memuatkan fail RDB yang terlalu besar Lumpuhkan halaman memori yang besar dan gunakan halaman memori yang besar, walaupun jika perubahan pelanggan Data hanya 50B data, dan Redis perlu menyalin 2MB halaman besar. Apabila sejumlah besar arahan ditulis, sejumlah besar salinan akan dihasilkan, mengakibatkan prestasi yang lebih perlahan. Sama ada memori yang digunakan oleh Redis terlalu besar, menyebabkan pertukaran;Sama ada konfigurasi AOF adalah munasabah, anda boleh menetapkan item konfigurasi no-appendfsync-on-rewrite kepada ya untuk mengelakkan AOF menulis semula dan fsync bersaing untuk sumber IO cakera, menyebabkan kependaman Redis meningkat. Bigkey akan membawa beberapa siri masalah. Pembelajaran yang disyorkan:Tutorial pembelajaran Redis
Atas ialah kandungan terperinci Redis tiba-tiba perlahan? Mari analisa cara untuk menentukan sama ada Redis mempunyai masalah prestasi dan cara menyelesaikannya. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!