- vừa được xem lúc

OkHttp - Performance issues - Lưu ý khi sử dụng

0 0 51

Người đăng: ledangtuanbk

Theo Viblo Asia

Giới thiệu vấn đề

Gần đây bạn mình có gặp 1 vấn đề liên quan đến việc sử dụng Okhttp, bạn ấy và mình cùng tìm hiểu và đã tìm ra nguyên nhân. Mình viết bài này để tổng hợp lại và chia sẻ mọi người để tránh gặp phải vấn đề này.

OkHttp là gì

Nó là một http client rất dễ để sử dụng và được sử dụng rộng rãi. Tất cả các thông tin có thể xem trên trang chủ Code mẫu rất dễ sử dụng

OkHttpClient client = new OkHttpClient(); String run(String url) throws IOException { Request request = new Request.Builder() .url(url) .build(); try (Response response = client.newCall(request).execute()) { return response.body().string(); }
}

Trong project lúc đầu đang sử dụng version 3.9.0, mình dang dùng maven

 <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>3.9.0</version> </dependency>

Vấn đề gặp phải

Mình có 1 đoạn code như bên dưới

String url = "https://example.com"; for (int i = 0; i < 100; i++) { OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url(url) .build(); try (Response response = client.newCall(request).execute()) { System.out.println(response.body().string()); } }

Nó gọi 1 Http Get bất kỳ, trong ví dụ này mình để gọi đến trang example.com Nhìn có vẻ ổn nhưng vấn đề liên quan đến performance, mình dùng tool VisualVM để quan sát, xem bài giới thiệu về tool VisualVM ở đây.

Mình gọi đoạn code trên 3 lần Chúng ta có thể thấy số lượng thread tăng lên trên 300 và chưa thấy dấu hiệu giảm, mỗi lần gọi nó sẽ tạo thread mới trong vòng for. Trong ví dụ này mình để loop 100 lần. mỗi lần gọi nó tăng thêm 100 threads

Nguyên nhân và Giải pháp

Nguyên nhân

Mỗi khi code được chạy, nó sẽ tạo mới 1 OkhttpClient, sau khi thoát hàm nó chưa kill thread đó ngay lập tức, nó sẽ hold lại 1 khoảng thời gian.

OkHttpClient client = new OkHttpClient();

Bản chất trong tài liệu của trang chủ

OkHttpClient client = new OkHttpClient(); String run(String url) throws IOException { Request request = new Request.Builder() .url(url) .build(); try (Response response = client.newCall(request).execute()) { return response.body().string(); }
}

Nó cũng tách cái OkHttpClient ra ngoài hàm, nhưng chúng ta đôi khi không để ý, thấy viết ngoài hàm để làm gì, vướng code, nên hay copy vào trong hàm luôn (sai lầm của dev bên mình, cái này không phải ai cũng biết, chỉ copy vào, thấy chạy được là chạy thôi).

Giải pháp

Di chuyển phần init ra bên ngoài, không để trong hàm nữa.

client chỉ cần init 1 lần

OkHttpClient client = new OkHttpClient();

Quan sát ta thấy lượng thread hầu như tăng không đáng kể.

Thay đổi version mới nhất (4.0.9)

Dường như bên phía OkHttp nhận ra điều này, họ đã update và sửa lỗi này. Nhưng không phải lúc nào cũng có thể thay đổi version của library, nhất là với những hệ thống đang hoạt động ổn định, có thể gây những lỗi (side-effect) mà thời điểm sửa chúng ta không phát hiện ra

Lời khuyên

Tùy vào tình huống, chúng ta có thể lựa chọn những phương pháp khác nhau để xử lý bài toán. Theo mình cái nào có thể handle được thì chúng ta handle, nếu tự tin và project đang trong quá trình phát triển thì có thể upgrade cả thư viện. Có thể tạo OkHttpClient dạng Singleton để giảm việc tạo nhiều object khi sử lý đa luồng.

public class OkhttpSingleton { private static volatile OkHttpClient instance; public static OkHttpClient getInstance() { // Do something before get instance ... if (instance == null) { // Do the task too long before create instance ... // Block so other threads cannot come into while initialize synchronized (OkhttpSingleton.class) { // Re-check again. Maybe another thread has initialized before if (instance == null) { instance = new OkHttpClient.Builder().build(); } } } // Do something after get instance ... return instance; }
}

Kết luận

Trong quá trình phát triển sản phẩm, ngoài yếu tố quan chạy được, chạy đúng, performance rất quan trọng. Khi project càng ngày càng lớn, lúc gặp vấn đề, chúng ta không biết xử lý từ đâu, chỗ nào gây lỗi. Việc cẩn thận khi code là rất quan trọng, chúng ta cẩn thận từ những cái nhỏ, chúng ta sẽ xây dựng được một project chạy ổn định lâu dài.

Nếu cần trao đổi thêm, hãy comment bên dưới.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Performance Optimization 104: Trinh sát ứng dụng với monitoring

Con đường trở thành thám tử chuyên nghiệp của chàng developer. Nếu bạn yêu ứng dụng của mình thì chỉ có cách cần trô thật chặt, thật kinh khủng, thật mất tự do vào.

0 0 57

- vừa được xem lúc

Performance Optimization 101: Những câu hỏi cơ bản

Definitive guide for performance engineer. API của bạn có thời gian phản hồi quá lâu. Hay hoá đơn cloud đập vào mặt bạn những con số quá kinh khủng dùng mới chỉ có một nhúm người dùng. HÃY ĐỌC TIẾP, BÀI VIẾT NÀY LÀ DÀNH CHO BẠN.

0 0 63

- vừa được xem lúc

Caching đại pháp 1: Nấc thang lên level của developer

Bí quyết thành công trong việc đáp ứng hệ thống triệu user của những công ty lớn (và cả công ty nhỏ). Tại sao caching lại là kỹ thuật tối quan trọng để phù phép ứng dụng rùa bò của chúng ta thành siêu phẩm vạn người mê.

0 0 82

- vừa được xem lúc

Performance Optimization 105: Database bottleneck - Đuổi bắt kẻ tội đồ

Hành trình đuổi bắt giáo sư Moriarty của thế giới bottleneck: database. Cuộc chiến không hồi kết này rút cục sẽ ra sao? Liệu mọi chuyện có kết thúc tại thác Reichenback không hay Moriarty sẽ mãi là bóng ma ám ảnh service của chúng ta mãi.

0 0 58

- vừa được xem lúc

Performance Optimization 103: Nghệ thuật tìm kiếm bottleneck

Những phương pháp thượng thừa để biến bạn trở thành bậc thầy bới lông tìm vết à bới hệ thống tìm bottleneck. Nếu là phe cảnh, bạn sẽ học được cách bắt bớ.

0 0 48

- vừa được xem lúc

Performance Optimization 102: Scalability và câu chuyện về ảo tưởng distributed

Performance, scalability cùng câu chuyện nỗi ám ảnh và những ảo tưởng của một developer về cái gọi là hệ thống distributed. .

0 0 63