Trong bài viết này chúng ta sẽ tìm hiểu về tính năng DBContext pooling.
Không có nhiều bài viết trên internet về tính năng tuyệt vời này, nó được chia sẻ bởi .NET Core team. Hãy xem DbContext làm việc ra sao trước .NET Core 2.1
AddDbContext
Nếu bạn đang làm việc với .NET Core, bạn có thể sẽ biết phương thức AddDbContext. Phương thức này sử dụng để khai báo DbContext với dependency injection và có thể inject được đói tượng DbContext vào controller. Và nó được đặt trong file Startup.cs. Để biết rõ hơn về DbContext có thể tham khảo tại đây
Bạn có thể tham khảo theo cách Code First và AddDbContext được dùng trong Starup.cs class.
Chúng ta sử dụng AddDbContext trong Startup.cs class:
services.AddDbContext<EmployeeContext>(options => options.UseSqlServer(connection));
Trường hợp của AddDbContext, một thể hiện của nó được tạo cho mỗi request và sẽ tự hủy khi công việc xong. Bạn có thể thấy là cứ mỗi một request đều có một đối tượng DbContext được tạo.
Nó vẫn chạy tốt nếu chỉ có khoảng 1000 request 1 lúc, vậy sẽ có 1000 đối tượng được tạo và hủy, trừ khi bạn dùng Singleton. Tạo và hủy quá nhiều đối tượng sẽ ảnh hưởng đến performance.
DbContextPooling giải quyết vấn đề như thế nào?
Nói một cách đơn giản thì DbContextPooling – là một bể chứa các đối tượng có thể được sử dụng lại được tạo ra. Thay vì mỗi lần chúng ta phải tạo mới đối tượng cho mỗi request, đầu tiên hệ thống sẽ kiểm tra xem có đối tượng nào có sẵn trong pool không?
Bạn có thể thấy ở hình trên, nếu có bất kỳ context nào có sẵn thì các context đó sẽ được dùng thay vì tạo mới các thể hiện mới. Điều này sẽ giảm số lượng context được tạo mới trong mỗi request.
Cũng thay vì hủy tất cả các thể hiện của context, nó được trả về cho pool và reset trạng thái của thể hiện về mặc định. Vì thế các thể hiện của context có thể được dùng trong tương lai.
Cách sử dụng DbContextPooling?
Đơn giản, chỉ cần thêm pool đằng sau AddDbContext như sau đây:
services.AddDbContextPool<EmployeeContext>(options => options.UseSqlServer(connection));
AddDbContextPool chấp nhận định nghĩa kiểu lamda expression
- Nếu có thêm một tham số kiểu integer chứa giá trị số lượng instance tối đa có thể chứa trong DbContext pool.
- Giá trị mặc định là 128
- Thay vì hủy toàn bộ đối tượng DbContext sau khi xong việc thì chúng lại được trả về pool và reset trạng thái về mặc định.
Nếu bạn muốn thay đổi số mặc định trong PoolSize bạn chỉ cần thêm:
services.AddDbContextPool<EmployeeContext>(options => options.UseSqlServer(connection),poolSize:128);
Kiểm tra hiệu năng
You might be wondering how much performance improvements can be achieved with this?
Bạn có thể tò mò về việc có thể tối ưu được hiệu năng nhiều không khi dùng nó? .NET Team đã tạo ra một POC nho nhỏ để đo hiệu năng sử dụng DbContextPooling và khi không dùng DbContextPooling bạn có thể xem code tại đây
Chương trình sẽ chạy một tét benchmark để đo chỉ số (request/giây) với một web đơn giản.
Ứng dụng sẽ chạy 10 giây và đo:
- Số context được tạo mỗi giây
- Số request mỗi giây
- Tổng số context được tạo
Sau đó hãy chạy và sử dụng AddDbContext không Pooling.
Kết quả là
Bạn có thể thấy:
- Số context được tạo mỗi giây
- Tổng số context được tạo là 19k+ trong 10 giây
- Trung bình request trên giây – 1839
Giờ hãy chạy AddDbContextPool với pooling.
Below is the result:
Có sự khác biệt thấy rõ
Bạn có thể thấy:
- Ứng dụng không tạo mới Context instance trong mỗi request vì nó được tái sử dụng lại
- Chỉ có 32 contexts được tạo trong 10 giây
- Trung bình mỗi giây có 2285 request
Final result
Như chúng ta đã thấy, sử dụng DbContextPooling, số lượng giảm đột ngột và giúp chương trình tăng hiệu năng lên rất nhiều. Trung bình số request trên giây, ứng dụng sẽ xử lý nhanh hơn trước kia. Chú ý đây là một POC rất nhỏ và kết quả có thể sẽ khác biệt lớn hơn khi sử dụng trong ứng dụng lớn hơn.
Trích nguồn từ: (https://neelbhatt.com/2018/02/27/use-dbcontextpooling-to-improve-the-performance-net-core-2-1-feature/)