Mengukur masa pelaksanaan permintaan kepada perkhidmatan luaran adalah penting untuk pemantauan dan pengoptimuman prestasi. Walau bagaimanapun, apabila sambungan kepada perkhidmatan luaran ini dikumpulkan, anda mungkin secara tidak sengaja mengukur lebih daripada sekadar masa permintaan. Khususnya, jika permintaan mengambil masa terlalu lama dan anda kehabisan sambungan yang tersedia, logik tersuai anda mungkin mula termasuk masa menunggu untuk mendapatkan sambungan daripada kolam. Ini boleh membawa kepada metrik yang mengelirukan, menyebabkan anda tersalah tafsir prestasi sistem anda. Mari kita teliti bagaimana perkara ini berlaku dan bagaimana anda boleh mengelak daripada tertipu oleh metrik anda sendiri.
Apabila semua sambungan dalam kolam sedang digunakan, permintaan tambahan mesti menunggu sehingga sambungan tersedia. Masa menunggu ini boleh memesongkan metrik anda jika tidak diukur secara berasingan daripada masa permintaan sebenar.
Jika logik tersuai anda mengukur jumlah masa sejak permintaan dibuat sehingga respons diterima, anda termasuk kedua-dua masa menunggu dan masa permintaan.
Untuk menggambarkan cara anda boleh tertipu oleh metrik anda sendiri dalam persekitaran terkumpul sambungan, mari kita lihat contoh praktikal menggunakan Spring Boot dan Apache HttpClient 5. Kami akan menyediakan aplikasi Spring Boot yang ringkas yang membuat permintaan HTTP untuk perkhidmatan luaran, ukur masa pelaksanaan permintaan ini dan tunjukkan cara keletihan kumpulan sambungan boleh membawa kepada metrik yang mengelirukan.
Untuk mensimulasikan kelewatan dalam perkhidmatan luaran, kami akan menggunakan imej httpbin Docker. Httpbin menyediakan perkhidmatan permintaan dan respons HTTP yang mudah digunakan, yang boleh kami gunakan untuk membuat kelewatan buatan dalam permintaan kami.
@SpringBootApplication @RestController public class Server { public static void main(String... args) { SpringApplication.run(Server.class, args); } class TimeClientHttpRequestInterceptor implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { var t0 = System.currentTimeMillis(); try { return execution.execute(request, body); } finally { System.out.println("Request took: " + (System.currentTimeMillis() - t0) + "ms"); } } } @Bean public RestClient restClient() { var connectionManager = new PoolingHttpClientConnectionManager(); connectionManager.setMaxTotal(2); // Max number of connections in the pool connectionManager.setDefaultMaxPerRoute(2); // Max number of connections per route return RestClient.builder()// .requestFactory(new HttpComponentsClientHttpRequestFactory( HttpClients.custom().setConnectionManager(connectionManager).build())) .baseUrl("http://localhost:9091")// .requestInterceptor(new TimeClientHttpRequestInterceptor()).build(); } @GetMapping("/") String hello() { return restClient().get().uri("/delay/2").retrieve().body(String.class); } }
Dalam kod di atas kami mencipta pemintas permintaan (ClientHttpRequestInterceptor) untuk mengukur masa yang kami fikir akan menjadi masa pelaksanaan permintaan kepada perkhidmatan luaran yang disokong oleh httpbin.
Kami juga secara eksplisit menetapkan kolam kepada saiz yang sangat kecil iaitu 2 sambungan untuk memudahkan masalah menghasilkan semula.
Kini kami hanya perlu memulakan httpbin, jalankan apl but spring kami dan jalankan ujian mudah menggunakan ab
$ docker run -p 9091:80 kennethreitz/httpbin
ab -n 10 -c 4 http://localhost:8080/ ... Percentage of the requests served within a certain time (ms) 50% 4049 66% 4054 75% 4055 80% 4055 90% 4057 95% 4057 98% 4057 99% 4057 100% 4057 (longest request)
Request took: 2021ms Request took: 2016ms Request took: 2022ms Request took: 4040ms Request took: 4047ms Request took: 4030ms Request took: 4037ms Request took: 4043ms Request took: 4050ms Request took: 4034ms
Jika kita melihat nombor, kita dapat melihat bahawa walaupun kita menetapkan kelewatan buatan selama 2 saat untuk pelayan luaran, kita sebenarnya mendapat kelewatan selama 4 saat untuk kebanyakan permintaan. Selain itu, kami mendapati bahawa hanya permintaan pertama memenuhi kelewatan yang dikonfigurasikan selama 2 saat, manakala permintaan seterusnya mengakibatkan kelewatan selama 4 saat.
Profil adalah penting apabila menghadapi gelagat kod pelik kerana ia mengenal pasti kesesakan prestasi, mendedahkan isu tersembunyi seperti kebocoran memori dan menunjukkan cara aplikasi anda menggunakan sumber sistem.
Kali ini kami akan memprofilkan apl yang sedang berjalan menggunakan JFR semasa menjalankan ujian beban ab.
$ jcmd <pid> JFR.start name=app-profile duration=60s filename=app-profile-$(date +%FT%H-%M-%S).jfr
$ ab -n 50 -c 4 http://localhost:8080/ ... Percentage of the requests served within a certain time (ms) 50% 4043 66% 4051 75% 4057 80% 4060 90% 4066 95% 4068 98% 4077 99% 4077 100% 4077 (longest request)
Jika kami membuka fail JFR dan melihat pada flamegraph, kami dapat melihat bahawa kebanyakan masa pelaksanaan dibelanjakan oleh klien HTTP kami. Masa pelaksanaan pelanggan dibahagikan antara menunggu perkhidmatan luaran kami bertindak balas dan menunggu untuk mendapatkan sambungan daripada kumpulan.
Itu menjelaskan sebab masa tindak balas yang kami lihat adalah dua kali ganda daripada jangkaan kelewatan tetap selama 2 saat yang kami tetapkan untuk pelayan luaran kami. Kami mengkonfigurasi kumpulan 2 sambungan. Walau bagaimanapun, dalam ujian kami, kami melaksanakan 4 permintaan serentak. Jadi, hanya 2 permintaan pertama akan disampaikan dalam jangka masa 2 saat. Permintaan seterusnya perlu menunggu kolam untuk melepaskan sambungan, sekali gus meningkatkan masa tindak balas yang diperhatikan.
Jika kita melihat pada flamegraph sekali lagi, kita juga boleh mengetahui mengapa masa yang diukur oleh ClientHttpRequestInterceptor kami tidak menggambarkan masa yang diambil oleh pelayan luaran untuk bertindak balas tetapi masa yang diperlukan untuk mendapatkan sambungan dari kolam ditambah masa yang diperlukan untuk melaksanakan permintaan sebenar kepada pelayan luaran. Pemintas kami sebenarnya sedang membungkus jejak tindanan yang akhirnya memanggil pengurus kolam untuk mendapatkan sambungan: PoolingHttpClientConnectionManager
Memantau masa tindak balas mana-mana klien HTTP sebaiknya dilakukan menggunakan metrik terbina dalamnya kerana metrik ini direka khusus untuk menangkap maklumat pemasaan yang tepat. Mereka mengambil kira semua aspek kitaran hayat permintaan HTTP, termasuk pemerolehan sambungan, penghantaran data dan pengendalian tindak balas. Ini memastikan bahawa ukuran adalah tepat dan konsisten dengan prestasi sebenar pelanggan.
Atas ialah kandungan terperinci Metrik Boleh Menipu Anda: Mengukur Masa Pelaksanaan dalam Persekitaran Disatukan Sambungan. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!