Cassandra. Làm thế nào để không chết nếu bạn chỉ biết Oracle

Xin chào, Habr.

Tên tôi là Misha Butrimov, tôi muốn kể cho bạn nghe một chút về Cassandra. Câu chuyện của tôi sẽ hữu ích cho những người chưa từng gặp phải cơ sở dữ liệu NoSQL - nó có rất nhiều tính năng triển khai và cạm bẫy mà bạn cần biết. Và nếu bạn chưa thấy thứ gì khác ngoài Oracle hoặc bất kỳ cơ sở dữ liệu quan hệ nào khác, những thứ này sẽ cứu mạng bạn.

Cassandra có gì hay? Đó là một cơ sở dữ liệu NoSQL được thiết kế không có một điểm lỗi nào và có quy mô tốt. Nếu bạn cần thêm vài terabyte cho một số cơ sở dữ liệu, bạn chỉ cần thêm các nút vào vòng. Mở rộng nó sang một trung tâm dữ liệu khác? Thêm các nút vào cụm. Tăng RPS được xử lý? Thêm các nút vào cụm. Nó cũng hoạt động theo hướng ngược lại.

Cassandra. Làm thế nào để không chết nếu bạn chỉ biết Oracle

Cô ấy còn giỏi cái gì nữa? Đó là về việc xử lý rất nhiều yêu cầu. Nhưng bao nhiêu là nhiều? 10, 20, 30, 40 nghìn yêu cầu mỗi giây là không nhiều. 100 nghìn yêu cầu mỗi giây để ghi - cũng vậy. Có những công ty cho biết họ lưu giữ 2 triệu yêu cầu mỗi giây. Có lẽ họ sẽ phải tin điều đó.

Và về nguyên tắc, Cassandra có một điểm khác biệt lớn so với dữ liệu quan hệ - nó không giống chúng chút nào. Và điều này rất quan trọng cần nhớ.

Không phải mọi thứ trông giống nhau đều hoạt động giống nhau

Có lần một đồng nghiệp đến gặp tôi và hỏi: “Đây là ngôn ngữ truy vấn CQL Cassandra và nó có một câu lệnh chọn, nó có vị trí, nó có và. Tôi viết thư và nó không hoạt động. Tại sao?". Đối xử với Cassandra như một cơ sở dữ liệu quan hệ là cách hoàn hảo để tự sát bằng bạo lực. Và tôi không quảng bá nó, nó bị cấm ở Nga. Bạn sẽ thiết kế một cái gì đó sai.

Ví dụ: một khách hàng đến gặp chúng tôi và nói: “Hãy xây dựng cơ sở dữ liệu cho phim truyền hình dài tập hoặc cơ sở dữ liệu cho danh mục công thức nấu ăn. Chúng tôi sẽ có các món ăn ở đó hoặc danh sách phim truyền hình và diễn viên trong đó ”. Chúng tôi vui vẻ nói: “Đi thôi!” Chỉ cần gửi hai byte, một vài dấu hiệu là xong, mọi thứ sẽ hoạt động rất nhanh chóng và đáng tin cậy. Và mọi chuyện vẫn ổn cho đến khi khách hàng đến và nói rằng các bà nội trợ cũng đang giải quyết vấn đề ngược lại: họ có danh sách sản phẩm và muốn biết mình muốn nấu món gì. Bạn đã chết.

Điều này là do Cassandra là cơ sở dữ liệu kết hợp: nó đồng thời cung cấp một giá trị khóa và lưu trữ dữ liệu trong các cột rộng. Trong Java hoặc Kotlin, nó có thể được mô tả như thế này:

Map<RowKey, SortedMap<ColumnKey, ColumnValue>>

Tức là một bản đồ cũng chứa một bản đồ đã được sắp xếp. Chìa khóa đầu tiên của bản đồ này là phím Hàng hoặc phím Phân vùng - phím phân vùng. Khóa thứ hai, là chìa khóa cho bản đồ đã được sắp xếp, là Khóa Phân cụm.

Để minh họa sự phân bố của cơ sở dữ liệu, hãy vẽ ba nút. Bây giờ bạn cần hiểu cách phân tách dữ liệu thành các nút. Bởi vì nếu chúng ta nhồi nhét mọi thứ vào một (nhân tiện, có thể có một nghìn, hai nghìn, năm - bao nhiêu tùy thích), thì đây thực sự không phải là vấn đề phân phối. Vì vậy, chúng ta cần một hàm toán học sẽ trả về một số. Chỉ là một con số, một int dài sẽ rơi vào một phạm vi nào đó. Và chúng ta sẽ có một nút chịu trách nhiệm cho một phạm vi, nút thứ hai cho phạm vi thứ hai, nút thứ n cho phạm vi thứ n.

Cassandra. Làm thế nào để không chết nếu bạn chỉ biết Oracle

Số này được lấy bằng hàm băm, được áp dụng cho cái mà chúng ta gọi là Khóa phân vùng. Đây là cột được chỉ định trong chỉ thị Khóa chính và đây là cột sẽ là khóa đầu tiên và cơ bản nhất của bản đồ. Nó xác định nút nào sẽ nhận dữ liệu nào. Một bảng được tạo trong Cassandra với cú pháp gần như giống như trong SQL:

CREATE TABLE users (
	user_id uu id,
	name text,
	year int,
	salary float,
	PRIMARY KEY(user_id)

)

Khóa chính trong trường hợp này bao gồm một cột và nó cũng là khóa phân vùng.

Người dùng của chúng tôi sẽ hoạt động như thế nào? Một số sẽ đến nút này, một số đến nút khác và một số đến nút thứ ba. Kết quả là một bảng băm thông thường hay còn gọi là bản đồ hay còn gọi là từ điển trong Python hoặc một cấu trúc giá trị Key đơn giản mà từ đó chúng ta có thể đọc tất cả các giá trị, đọc và ghi theo khóa.

Cassandra. Làm thế nào để không chết nếu bạn chỉ biết Oracle

Chọn: khi cho phép lọc chuyển sang quét toàn bộ hoặc không nên làm gì

Hãy viết một số câu lệnh chọn: select * from users where, userid = . Hóa ra giống như trong Oracle: chúng tôi viết chọn, chỉ định các điều kiện và mọi thứ đều hoạt động, người dùng hiểu. Nhưng nếu bạn chọn, chẳng hạn, một người dùng có năm sinh nhất định, Cassandra sẽ phàn nàn rằng họ không thể thực hiện yêu cầu. Bởi vì cô ấy hoàn toàn không biết gì về cách chúng tôi phân phối dữ liệu về năm sinh - cô ấy chỉ có một cột được biểu thị làm khóa. Sau đó cô ấy nói: “Được rồi, tôi vẫn có thể đáp ứng yêu cầu này. Thêm cho phép lọc." Chúng tôi thêm chỉ thị, mọi thứ đều hoạt động. Và vào lúc này một điều gì đó khủng khiếp xảy ra.

Khi chúng tôi chạy trên dữ liệu thử nghiệm, mọi thứ đều ổn. Và khi bạn thực hiện một truy vấn trong quá trình sản xuất, chẳng hạn như nơi chúng tôi có 4 triệu bản ghi, thì mọi thứ đều không tốt cho chúng tôi. Bởi vì cho phép lọc là một lệnh cho phép Cassandra thu thập tất cả dữ liệu từ bảng này từ tất cả các nút, tất cả các trung tâm dữ liệu (nếu có nhiều dữ liệu trong cụm này) và chỉ sau đó lọc nó. Đây là một tính năng tương tự của Full Scan và hầu như không ai hài lòng với nó.

Nếu chúng tôi chỉ cần người dùng theo ID, chúng tôi sẽ ổn với điều này. Nhưng đôi khi chúng ta cần viết các truy vấn khác và áp đặt các hạn chế khác đối với việc lựa chọn. Vì vậy, chúng ta nhớ: đây đều là bản đồ có khóa phân vùng nhưng bên trong là bản đồ đã được sắp xếp.

Và cô ấy cũng có một khóa mà chúng tôi gọi là Khóa phân cụm. Khóa này lần lượt bao gồm các cột mà chúng tôi chọn, với sự trợ giúp của Cassandra hiểu cách dữ liệu của nó được sắp xếp vật lý và sẽ nằm trên mỗi nút. Nghĩa là, đối với một số khóa Phân vùng, phím Clustering sẽ cho bạn biết chính xác cách đẩy dữ liệu vào cây này, nó sẽ chiếm vị trí nào trong đó.

Đây thực sự là một cái cây, một bộ so sánh được gọi đơn giản ở đó, nơi chúng ta chuyển một tập hợp các cột nhất định dưới dạng một đối tượng và nó cũng được chỉ định dưới dạng danh sách các cột.

CREATE TABLE users_by_year_salary_id (
	user_id uuid,
	name text,
	year int,
	salary float,
	PRIMARY KEY((year), salary, user_id)

Hãy chú ý đến chỉ thị Khóa chính; đối số đầu tiên của nó (trong trường hợp của chúng tôi là năm) luôn là Khóa phân vùng. Nó có thể bao gồm một hoặc nhiều cột, không thành vấn đề. Nếu có nhiều cột thì cần bỏ lại trong ngoặc để bộ tiền xử lý ngôn ngữ hiểu đây là Primary key, đằng sau tất cả các cột còn lại là Clustering key. Trong trường hợp này, chúng sẽ được truyền đi trong bộ so sánh theo thứ tự xuất hiện của chúng. Nghĩa là, cột đầu tiên quan trọng hơn, cột thứ hai ít quan trọng hơn, v.v. Ví dụ: cách chúng tôi viết các trường bằng nhau cho các lớp dữ liệu: chúng tôi liệt kê các trường và đối với chúng, chúng tôi viết trường nào lớn hơn và trường nào nhỏ hơn. Trong Cassandra, nói một cách tương đối, đây là các trường của lớp dữ liệu mà các giá trị bằng được viết cho nó sẽ được áp dụng.

Chúng tôi sắp xếp và áp đặt các hạn chế

Bạn cần nhớ rằng thứ tự sắp xếp (giảm dần, tăng dần, bất cứ thứ gì) được đặt tại cùng thời điểm khi khóa được tạo và không thể thay đổi sau này. Nó xác định về mặt vật lý cách dữ liệu sẽ được sắp xếp và cách lưu trữ. Nếu cần thay đổi phím Clustering hoặc thứ tự sắp xếp, bạn sẽ phải tạo một bảng mới và chuyển dữ liệu vào đó. Điều này sẽ không hoạt động với một cái hiện có.

Cassandra. Làm thế nào để không chết nếu bạn chỉ biết Oracle

Chúng tôi lấp đầy bảng của mình với những người dùng và thấy rằng họ rơi vào một vòng, đầu tiên là theo năm sinh, sau đó vào mỗi nút theo mức lương và ID người dùng. Bây giờ chúng ta có thể chọn bằng cách áp đặt các hạn chế.

Công việc của chúng tôi lại xuất hiện where, and, và chúng tôi có người dùng, mọi thứ lại ổn. Nhưng nếu chúng ta cố gắng chỉ sử dụng một phần của khóa Phân cụm và một phần ít quan trọng hơn, thì Cassandra sẽ ngay lập tức phàn nàn rằng nó không thể tìm thấy vị trí trên bản đồ của chúng ta nơi đối tượng này, nơi có các trường này cho bộ so sánh null và trường này nó vừa mới được sắp đặt - nơi anh ấy nằm. Tôi sẽ phải lấy lại tất cả dữ liệu từ nút này và lọc nó. Và đây là một dạng tương tự của Quét toàn bộ trong một nút, điều này thật tệ.

Trong mọi tình huống không rõ ràng, hãy tạo một bảng mới

Nếu muốn có thể target người dùng theo ID, hay theo độ tuổi, hay theo lương thì chúng ta phải làm như thế nào? Không có gì. Chỉ cần sử dụng hai bảng. Nếu bạn cần tiếp cận người dùng theo ba cách khác nhau thì sẽ có ba bảng. Đã qua rồi cái thời chúng ta tiết kiệm không gian trên vít. Đây là nguồn tài nguyên rẻ nhất. Chi phí này thấp hơn nhiều so với thời gian phản hồi, điều này có thể gây bất lợi cho người dùng. Sẽ dễ chịu hơn nhiều khi người dùng nhận được thứ gì đó trong một giây thay vì trong 10 phút.

Chúng tôi đánh đổi không gian không cần thiết và dữ liệu không chuẩn hóa để có khả năng mở rộng quy mô tốt và hoạt động đáng tin cậy. Trên thực tế, một cụm bao gồm ba trung tâm dữ liệu, mỗi trung tâm có năm nút, với mức độ bảo toàn dữ liệu có thể chấp nhận được (khi không có gì bị mất), có thể tồn tại hoàn toàn sau khi một trung tâm dữ liệu ngừng hoạt động. Và hai nút nữa ở mỗi nút trong số hai nút còn lại. Và chỉ sau đó các vấn đề mới bắt đầu. Đây là một sự dư thừa khá tốt, đáng để có thêm một vài ổ SSD và bộ xử lý. Vì vậy, để sử dụng Cassandra, vốn không bao giờ là SQL, trong đó không có mối quan hệ, khóa ngoại, bạn cần biết các quy tắc đơn giản.

Chúng tôi thiết kế mọi thứ theo yêu cầu của bạn. Điều chính không phải là dữ liệu mà là cách ứng dụng sẽ hoạt động với nó. Nếu nó cần nhận dữ liệu khác nhau theo những cách khác nhau hoặc cùng một dữ liệu theo những cách khác nhau, chúng ta phải sắp xếp nó theo cách thuận tiện cho ứng dụng. Nếu không, chúng tôi sẽ thất bại trong Quét toàn bộ và Cassandra sẽ không mang lại cho chúng tôi bất kỳ lợi thế nào.

Dữ liệu không chuẩn hóa là tiêu chuẩn. Chúng ta quên đi các biểu mẫu thông thường, chúng ta không còn cơ sở dữ liệu quan hệ nữa. Nếu chúng ta đặt vật gì đó xuống 100 lần thì nó sẽ nằm xuống 100 lần. Nó vẫn rẻ hơn so với việc dừng lại.

Chúng tôi chọn các khóa để phân vùng để chúng được phân phối bình thường. Chúng tôi không muốn hàm băm của khóa rơi vào một phạm vi hẹp. Tức là năm sinh trong ví dụ trên là một ví dụ tồi. Chính xác hơn, sẽ tốt nếu người dùng của chúng ta thường được phân bổ theo năm sinh, và thật tệ nếu chúng ta đang nói về học sinh lớp 5 - việc phân vùng ở đó sẽ không tốt lắm.

Sắp xếp được chọn một lần ở giai đoạn tạo Khóa phân cụm. Nếu cần thay đổi, chúng ta sẽ phải cập nhật bảng của mình bằng một khóa khác.

Và điều quan trọng nhất: nếu chúng ta cần lấy cùng một dữ liệu theo 100 cách khác nhau thì chúng ta sẽ có 100 bảng khác nhau.

Nguồn: www.habr.com

Thêm một lời nhận xét