Apakah ada cara saya dapat membuat Nginx untuk memberi tahu saya jika klik dari pengarah melampaui ambang batas?
mis. Jika situs web saya ditampilkan di Slashdot dan tiba-tiba saya mendapat 2K hit dalam satu jam, saya ingin diberi tahu ketika melampaui 1K hit satu jam.
Apakah mungkin untuk melakukan ini di Nginx? Mungkin tanpa lua? (karena prod saya tidak dikompilasi)
Jawaban:
Solusi yang paling efisien mungkin untuk menulis sebuah daemon yang akan
tail -f
denganaccess.log
, dan melacak$http_referer
lapangan.Namun, solusi cepat dan kotor adalah menambahkan
access_log
file tambahan , hanya mencatat$http_referer
variabel dengan kustomlog_format
, dan memutar log secara otomatis setiap X menit.Ini dapat dilakukan dengan bantuan skrip logrotate standar, yang mungkin perlu melakukan restart nginx agar file dibuka kembali (misalnya, prosedur standar, lihat / a / 15183322 pada SO untuk waktu yang sederhana- skrip berbasis) ...
Atau, dengan menggunakan variabel di dalamnya
access_log
, mungkin dengan mengeluarkan spesifikasi menit$time_iso8601
dengan bantuanmap
atauif
arahan (tergantung di mana Anda ingin menempatkan Andaaccess_log
).Jadi, dengan yang di atas, Anda mungkin memiliki 6 file log, masing-masing mencakup periode 10 menit
http_referer.Txx{0,1,2,3,4,5}x.log
, misalnya, dengan mendapatkan digit pertama dari menit untuk membedakan setiap file.Sekarang, yang harus Anda lakukan adalah memiliki skrip shell sederhana yang dapat berjalan setiap 10 menit,
cat
semua file di atas, pipa kesort
, pipa keuniq -c
, kesort -rn
, kehead -16
, dan Anda memiliki daftar 16Referer
variasi paling umum - bebas memutuskan apakah kombinasi angka dan bidang melebihi kriteria Anda, dan melakukan pemberitahuan.Selanjutnya, setelah satu pemberitahuan berhasil, Anda dapat menghapus semua 6 file ini, dan, dalam menjalankan selanjutnya, tidak mengeluarkan pemberitahuan KECUALI semua enam file hadir (dan / atau nomor lain tertentu sesuai keinginan Anda).
sumber
Saya pikir ini akan jauh lebih baik dilakukan dengan logtail dan grep. Bahkan jika itu mungkin dilakukan dengan lua inline, Anda tidak ingin overhead itu untuk setiap permintaan dan Anda terutama tidak menginginkannya ketika Anda telah Slashdotted.
Ini versi 5 detik. Tempelkan di skrip dan letakkan beberapa teks yang lebih mudah dibaca di sekitarnya dan Anda menjadi emas.
Tentu saja, itu sepenuhnya mengabaikan reddit.com dan facebook.com dan semua juta situs lain yang dapat mengirimkan banyak lalu lintas kepada Anda. Belum lagi 100 situs yang berbeda mengirimkan Anda masing-masing 20 pengunjung. Anda mungkin hanya memiliki ambang lalu lintas lama polos yang menyebabkan email dikirimkan kepada Anda, terlepas dari pengarah.
sumber
-o
Pilihannya adalah untuk file offset sehingga tahu di mana harus mulai membaca waktu berikutnya.Arahan nginx limit_req_zone dapat mendasarkan zona pada variabel apa pun, termasuk $ http_referrer.
Anda juga akan ingin melakukan sesuatu untuk membatasi jumlah negara yang diperlukan pada server web, karena header pengarah bisa sangat panjang dan bervariasi dan Anda mungkin melihat variet infinte. Anda dapat menggunakan fitur nginx split_clients untuk mengatur variabel untuk semua permintaan yang didasarkan pada hash dari header pengarah. Contoh di bawah ini hanya menggunakan 10 buckes, tetapi Anda dapat melakukannya dengan 1000 dengan mudah. Jadi, jika Anda memiliki slashdotted, orang-orang yang perujuknya hash ke dalam ember yang sama dengan URL slashdot juga akan diblokir, tetapi Anda dapat membatasi itu hingga 0,1% pengunjung dengan menggunakan 1000 ember di split_clients.
Akan terlihat seperti ini (benar-benar belum diuji, tetapi benar secara arah):
sumber
split_clients
mungkin salah informasi -limit_req
didasarkan pada "ember bocor", yang berarti bahwa keadaan keseluruhan tidak boleh melebihi ukuran zona yang ditentukan.Ya, tentu saja mungkin di NGINX!
Yang bisa Anda lakukan adalah menerapkan DFA berikut :
Terapkan pembatasan tarif, berdasarkan
$http_referer
, mungkin menggunakan beberapa regex melalui amap
untuk menormalkan nilai-nilai. Ketika batas terlampaui, halaman kesalahan internal dinaikkan, yang dapat Anda tangkap melaluierror_page
penangan sesuai pertanyaan terkait , pergi ke lokasi internal baru sebagai pengalihan internal (tidak terlihat oleh klien).Di lokasi di atas untuk batas terlampaui, Anda melakukan permintaan peringatan, membiarkan logika eksternal melakukan pemberitahuan; permintaan ini selanjutnya di-cache, memastikan Anda hanya akan mendapatkan 1 permintaan unik per jendela waktu tertentu.
Tangkap kode Status HTTP dari permintaan sebelumnya (dengan mengembalikan kode status ≥ 300 dan menggunakan
proxy_intercept_errors on
, atau, alternatifnya, gunakan not-built-by-defaultauth_request
atauadd_after_body
untuk membuat subrequest "bebas"), dan lengkapi permintaan asli seolah-olah langkah sebelumnya tidak terlibat. Perhatikan bahwa kita perlu mengaktifkanerror_page
penanganan rekursif agar ini berfungsi.Ini PoC dan MVP saya, juga di https://github.com/cnst/StackOverflow.cnst.nginx.conf/blob/master/sf.432636. Mendeteksi-slashdot-effect-in-nginx.conf :
Perhatikan bahwa ini berfungsi seperti yang diharapkan:
Anda dapat melihat bahwa permintaan pertama menghasilkan satu front-end dan satu pukulan backend, seperti yang diharapkan (saya harus menambahkan backend dummy ke lokasi yang telah
limit_req
, karenareturn 200
akan didahulukan dari batas, backend nyata tidak diperlukan selama sisa penanganan).Permintaan kedua adalah di atas batas, jadi, kami mengirim peringatan (mendapatkan
200
), dan menyimpannya, mengembalikan429
(ini diperlukan karena batasan yang disebutkan sebelumnya bahwa permintaan di bawah 300 tidak dapat ditangkap), yang kemudian ditangkap oleh front-end , yang bebas sekarang bebas untuk melakukan apa pun yang diinginkannya.Permintaan ketiga masih melebihi batas, tetapi kami sudah mengirimkan lansiran, jadi, tidak ada lansiran baru yang dikirim.
Selesai! Jangan lupa untuk memotongnya di GitHub!
sumber
limit_req
, dan yang lainnya adalahlimit_conn
, maka gunakan saja dilimit_req_status 429
atas (membutuhkan nginx yang sangat baru), dan saya pikir Anda harus menjadi emas; mungkin ada opsi lain (satu untuk bekerja pasti adalah chaining nginx w /set_real_ip_from
, tetapi, tergantung pada apa yang ingin Anda lakukan, mungkin ada pilihan yang lebih efisien).golang
, atau mencari opsi batas waktu untuk upstreams; juga, mungkin ingin menggunakanproxy_cache_lock on
juga, dan mungkin menambahkan beberapa penanganan kesalahan untuk apa yang harus dilakukan jika skrip gagal (misalnya, menggunakanerror_page
dan jugaproxy_intercept_errors
lagi). Saya percaya POC saya adalah awal yang baik. :)limit_req
/limit_conn
? Misalnya, letakkan konfigurasi di atas di depan server front-end Anda saat ini. Anda dapat menggunakanset_real_ip_from
di hulu nginx untuk memastikan IP dicatat dengan benar di telepon. Selain itu, jika masih tidak sesuai, saya pikir Anda harus mengartikulasikan kendala dan spesifikasi Anda dengan lebih jelas - tingkat lalu lintas apa yang sedang kita bicarakan? Seberapa sering stat harus dijalankan (1 menit / 5 menit / 1 jam)? Apa yang salah denganlogtail
solusi lama ?