Chia sẻ kiến thức lập trình

Freechat – Lựa chọn database

Tranh luận không hồi kết

Giá như thế giới chỉ có một lựa chọn duy nhất thì có phải tốt không nhỉ? Có phải đỡ đau đầu lựa chọn giữa cái này cái kia, các anh em cũng đỡ phải tranh luận cái này hay hơn cái kia, đỡ mất tinh thần đoàn kết hay không, 🙂

Hiện tại chúng ta đang tồn tại hai kiểu cơ sở dữ liệu chính:

  1. NoSQL: loại cơ sở dữ liệu ít quan hệ, chúng ta sẽ thường tổ chức dữ liệu ở dạng key-value để lưu trữ và truy xuất nhanh. Các hệ quản trị cơ sở dữ liệu dạng này cũng không hỗ trợ các câu lệnh join phức tạp (thậm chí là không hỗ trợ câu lệnh join luôn). Muốn join được các bảng, chúng ta sẽ cần làm ở tầng ứng dụng. Một số hệ quản trị cơ sở dữ liệu nổi bật với NoSQL hiện nay đó là: MongoDB, HBase và Cassandra
  2. MySQL: ra đời trước NoSQL và phổ biến hơn NoSQL, loại cơ sở dữ liệu này thường được tổ chức thành các bảng phức tạp, được liên kết với nhau thông qua khoá chính và khoá ngoại. Các hệ quản trị cơ sở dữ liệu quan hệ thường hỗ trợ các câu lệnh join rất mạnh, một trong các số đó phải nói đến: MySQL, Oracle, SQL Server, PostgreSQL

Lựa chọn không dễ dàng

Đầu tiên chúng ta hãy nói đến ứng dụng chat của chúng ta.

  1. Chúng ta mong muốn Freechat sẽ đạt được 10.000 message mỗi ngày, vậy 1 năm chúng ta sẽ có 3.650.000 message
  2. Sẽ có 2 chức năng chính đó là lưu lại message và lấy danh sách các message cũ, đối với các nghiệp vụ tìm kiếm message phức tạp chúng ta sẽ truy vấn thông qua hệ thống elasticsearch riêng

Với số lượng message khiêm tốn và yêu cầu đơn giản như trên thì thực ra dùng cơ sở dữ liệu nào cũng được, tuy nhiên chúng ta vẫn muốn có sự lựa chọn đơn giản và đạt hiệu suất cao nhất.

Dù có đọc bao nhiêu tài liệu, có nghe bao nhiêu người nói đi chăng nữa cũng không bằng việc chúng ta bắt tay luôn vào test thử với MongoDB và MySQL.

Tiến hành thử nghiệm

Kịch bản thử nghiệm sẽ là: insert 10.000 message vào trong cơ sở dữ liệu và đo thời gian. Message của chúng ta sẽ có dạng:

public class ChatMessage {
    private long id;
    private boolean read;
    private String message;
    private long channelId;
    private String sender;
    private String sentClientMessageId;
}

Đầu tiên, hãy bắt đầu với MongoDB

Với MongoDB

Bước 1: Tạo cơ sở dữ liệu và gán quyền truy cập như sau:

use freechat-test
db.createUser(
   {
     user:"freechat-test",
     pwd:"123456",
     roles:[ { role: "readWrite", db: "freechat-test" }]
   }
)

Bước 2. Tạo đối tượng Repository để giao tiếp với cơ sở dữ liệu:

EzyDatabaseContext context = new EzyMongoDatabaseContextBuilder()
    .build();
return context.getRepository(MongoMessageRepository.class);

Bước 3. Lưu 10.000 message vào cơ sở dữ liệu

long start = System.currentTimeMillis();
for(List<ChatMessage> messageList : messageLists) {
    for(ChatMessage message : messageList) {
        repo.save(message);
    }
}
long elapsedTime = System.currentTimeMillis() - start;
System.out.println(elapsedTime);

Ví dụ đầy đủ, bạn có thể tham khảo tại đây

Bước 4. Thực thi và chúng ta nhận được kết quả: 3782 millis giây

Với MySQL

Bước 1: Tạo cơ sở dữ liệu và bảng như sau:

CREATE SCHEMA `freechat-test` DEFAULT CHARACTER SET utf8mb4 ;
CREATE TABLE `message` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `isRead` tinyint(1) DEFAULT NULL,
  `message` varchar(300) DEFAULT NULL,
  `channelId` bigint DEFAULT NULL,
  `sender` varchar(45) DEFAULT NULL,
  `sentClientMessageId` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

Bước 2. Tạo đối tượng Repository để giao tiếp với cơ sở dữ liệu:

 private static MySQLMessageRepository getMessageRepository() {
    EzyDatabaseContext context = databaseContext();
    return context.getRepository(MySQLMessageRepository.class);
}

private static EzyDatabaseContext databaseContext() {
    return new EzyJpaDatabaseContextBuilder()
        .build();
}

private static EntityManagerFactory entityManagerFactory() {
    return new EzyJpaEntityManagerFactoryLoader()
        .load("Test");
}

private static DataSource dataSource() {
    return new EzyJpaDataSourceLoader()
        .load();
}

Bước 3. Lưu 10.000 message vào cơ sở dữ liệu

long start = System.currentTimeMillis();
for(List<ChatMessage> messageList : messageLists) {
    for(ChatMessage message : messageList) {
        repo.save(message);
    }
}
long elapsedTime = System.currentTimeMillis() - start;
System.out.println(elapsedTime);

Ví dụ đầy đủ, bạn có thể tham khảo tại đây

Bước 4. Thực thi và chúng ta nhận được kết quả: 38101 millis giây

Kết luận

Rõ ràng MongoDB (NoSQL) đơn giản hơn so với MySQL (SQL) rất nhiều kể từ việc tạo bảng cho đến cấu hình trong code. Thêm vào nữa đó là tốc độ lưu trữ của MongoDB nhanh hơn MySQL rất nhiều. Nên ở thời điểm hiện tại, bắt đầu dự án với thời gian và kinh phí eo hẹp, chúng ta sẽ lựa chọn MongoDB. Còn vì sao lại có sự khác biệt như vậy mình sẽ nói ở những bài viết khác nhé.

Tham khảo

  1. MongoDB Test
  2. MySQL Test
  3. Freechat web
  4. Freechat Github
Share: