Phân tích cấu trúc dữ liệu bên trong Redis Phân tích cấu trúc dữ liệu bên trong Redis Bài viết này là phần thứ năm trong series của chúng tôi. Trong nội dung hôm naybắn cá săn thưởng, chúng ta sẽ cùng tìm hiểu về một cấu trúc dữ liệu bên trong Redis – Kiểu dữ liệu list mà Redis cung cấp cho người dùng bên ngoài thực chất được xây dựng dựa trên cấu trúc dữ liệu quicklist ở bên trong. Quicklist đóng vai trò như nền tảng quan trọng giúp Redis quản lý và xử lý các thao tác liên quan đến danh sách một cách hiệu quả.
Trong quá trình thảo luậnmua thẻ trực tuyến, chúng ta sẽ còn đề cập đến hai cấu hình Redis quan trọng (ở phần ADVANCED CONFIG trong tệp redis.conf):
list-max-ziplist-size -2
list-compress-depth 0
Trong quá trình thảo luậnbắn cá săn thưởng, chúng tôi sẽ giải thích chi tiết ý nghĩa của hai cấu hình này.
Lưu ý: Thực hiện phân tích quicklist trong bài viết này dựa trên nhánh nguồn mã của Redis phiên bản 3.2.
Redis cung cấp kiểu dữ liệu danh sách (list) ở tầng giao tiếp phía trênbầu cua, thường được sử dụng như một hàng đợi (queue). Một số hoạt động mà nó hỗ trợ, chẳng hạn như: - Thêm phần tử vào cuối danh sách với lệnh `RPUSH`, cho phép bạn dễ dàng thêm nhiều giá trị cùng lúc. - Lấy phần tử từ đầu danh sách bằng cách sử dụng lệnh `LPOP`, giúp mô phỏng hành vi của một hàng đợi theo nguyên tắc "trước ra trước". - Thực hiện thao tác thêm và lấy phần tử từ cả hai đầu danh sách, ví dụ như thêm vào đầu bằng `LPUSH` và lấy từ cuối bằng `RPOP`. - Kết hợp với các tùy chọn như `BLPOP` hoặc `BRPOP` để chờ đợi sự kiện khi danh sách chưa có phần tử sẵn sàng. Những tính năng này làm cho Redis trở thành một lựa chọn tuyệt vời cho các ứng dụng yêu cầu xử lý dữ liệu tuần tự hiệu quả.
lpush
: Chèn dữ liệu vào bên trái (tức là phần đầu danh sách).
rpop
: Xóa dữ liệu từ bên phải (tức là phần cuối danh sách).
rpush
: Chèn dữ liệu vào bên phải (tức là phần cuối danh sách).
lpop
: Xóa dữ liệu từ bên trái (tức là phần đầu danh sách).
Những thao tác này có độ phức tạp thời gian O(1).
Tất nhiênmua thẻ trực tuyến, list cũng hỗ trợ thao tác truy cập tại bất kỳ vị trí nào giữa, chẳng hạn
lindex
Một quá trình đọc: Quá trình thứ
linsert
bắn cá săn thưởng, nhưng chúng đều yêu cầu duyệt qua toàn bộ list, do đó độ phức tạp thời gian cao hơn, là O(N).
Tóm lạimua thẻ trực tuyến, một list có những đặc điểm như sau: đây là một danh sách duy trì thứ tự của các phần tử (thứ tự được xác định bởi vị trí khi thêm vào), thuận tiện cho việc thêm và xóa dữ liệu ở cả hai đầu danh sách, nhưng việc truy xuất ở giữa sẽ có độ phức tạp thời gian là O(n). Điều này chẳng phải cũng chính là những đặc điểm của một danh sách liên kết đôi hay sao?
Thực hiện nội bộ của listbầu cua, quicklist, thực chất là một danh sách liên kết hai chiều. Trong phần chú thích đầ c, quicklist được mô tả như sau:
A doubly linked list of ziplists
Nó thực sự là một danh sách liên kết hai chiều và là một danh sách ziplist hai chiều.
Điều này có nghĩa là gì?
Chúng ta đều hiểu rằngbầu cua, danh sách liên kết hai chiều được cấu thành từ nhiều nút (node). Điều này có nghĩa là mỗi nút trong quicklist thực chất là một ziplist. Ziplist mà chúng ta đã tìm hiểu trước đây... Bài trước Đã được giới thiệu trước đó.
Ziplist về bản chất là một danh sách có khả năng duy trì thứ tự các mục dữ liệu theo thứ tự chúng được thêm vàobắn cá săn thưởng, và nó cũng là một loại danh sách tối ưu hóa bộ nhớ (các mục dữ liệu trong đó sẽ liên tiếp với nhau trong bộ nhớ). Ví dụ, một quicklist gồm 3 nút, mỗi nút ziplist lại chứa 4 mục dữ liệu, thì nhìn chung, danh sách này sẽ biểu hiện ra bên ngoài như thể nó chứa tổng cộng 12 mục dữ liệu. Điều này cho thấy cách mà ziplist và quicklist hoạt động hiệu quả để quản lý không gian bộ nhớ cũng như sắp xếp dữ liệu một cách hợp lý.
Tại sao cấu trúc của quicklist lại được thiết kế như vậy? Tóm lạimua thẻ trực tuyến, đó là một sự đánh đổi giữa không gian và thời gian: Để tối ưu hóa hiệu suất, quicklist được xây dựng với cơ chế lưu trữ thông minh, cho phép nó truy xuất dữ liệu nhanh chóng mà vẫn duy trì mức tiêu thụ tài nguyên hợp lý. Điều này giúp giảm thiểu thời gian tải, đồng thời tiết kiệm bộ nhớ trong quá trình sử dụng. Sự cân bằng này không chỉ cải thiện trải nghiệm người dùng mà còn tăng cường khả năng xử lý của hệ thống, đặc biệt khi làm việc với khối lượng lớn dữ liệu hoặc yêu cầu đa nhiệm phức tạp.
Do đómua thẻ trực tuyến, kết hợp các ưu điểm của danh sách liên kết hai chiều và ziplist, quicklist đã ra đời.
Tuy nhiênbắn cá săn thưởng, điều này cũng đặt ra một vấn đề mới: một nút quicklist nên chứa bao nhiêu phần tử trong ziplist là phù hợp đây? Ví dụ, cùng việc lưu trữ 12 mục dữ liệu, chúng ta có thể thiết lập một quicklist gồm 3 nút, mỗi nút ziplist chứa 4 mục dữ liệu; hoặc cũng có thể tạo một quicklist gồm 6 nút, mỗi nút ziplist chỉ chứa 2 mục dữ liệu. Sự lựa chọn này không đơn giản chỉ liên quan đến số lượng mà còn tác động trực tiếp đến hiệu suất và khả năng quản lý bộ nhớ của hệ thống. Liệu cấu hình nào sẽ tối ưu hơn giữa hai phương án trên? Điều này phụ thuộc vào yêu cầu cụ thể của ứng dụng và đặc điểm của môi trường vận hành.
Đây lại là một vấn đề cần tìm điểm cân bằng. Chúng ta chỉ phân tích ngắn gọn từ khía cạnh hiệu quả lưu trữ:
Rõ ràngbắn cá săn thưởng, một nút quicklist cần duy trì độ dài của ziplist ở mức hợp lý. Nhưng cụ thể bao nhiêu là hợp lý thì điều này có thể phụ thuộc vào ngữ cảnh ứng dụng cụ thể. Trên thực tế, Redis cung cấp một tham số cấu hình để giúp người dùng tùy chỉnh điều này. Trong nhiều trường hợp, việc tối ưu hóa kích thước ziplist đóng vai trò quan trọng trong việc cân bằng hiệu suất giữa bộ nhớ và tốc độ truy xuất. Tham số mà Redis cung cấp thường liên quan đến giới hạn tối đa của phần tử trong ziplist cũng như số lượng các nút quicklist được tạo ra. Người dùng có thể điều chỉnh tham số này dựa trên yêu cầu về dung lượng RAM và khối lượng dữ liệu mà hệ thống phải xử lý. Ví dụ, nếu ứng dụng của bạn chủ yếu làm việc với các dữ liệu nhỏ gọn và cần tốc độ cao, bạn có thể tăng giới hạn ziplist để giảm số lượng quicklist và cải thiện hiệu suất đọc ghi. Ngược lại, nếu tài nguyên RAM bị hạn chế hoặc dữ liệu lớn hơn, việc giảm kích thước ziplist có thể giúp tiết kiệm bộ nhớ. Tóm lại, việc hiểu rõ cách hoạt động của quicklist và ziplist, cùng với khả năng tùy chỉnh thông qua các tham số cấu hình của Redis, sẽ giúp bạn tối ưu hóa hiệu suất cho ứng dụng của mình một cách tốt nhất.
list-max-ziplist-size
bầu cua, nhằm cho phép người dùng điều chỉnh theo tình huống cụ thể của mình.
list-max-ziplist-size -2
Hãy giải thích chi tiết ý nghĩa của tham số này. Nó có thể nhận giá trị dương hoặc âm.
Khi giá trị được đặt thành dươngmua thẻ trực tuyến, điều này có nghĩa là giới hạn độ dài của ziplist trên mỗi nút quicklist sẽ được xác định dựa trên số lượng mục dữ liệu. Ví dụ, khi tham số này được cấu hình thành 5, điều đó có nghĩa là mỗi nút quicklist có thể chứa tối đa 5 mục dữ liệu trong ziplist của nó. Điều thú vị là việc thiết lập giới hạn như vậy giúp tối ưu hóa hiệu suất bộ nhớ và tăng tốc độ truy xuất dữ liệu. Khi số lượng mục dữ liệu tăng lên, việc giới hạn kích thước của ziplist sẽ đảm bảo rằng các nút quicklist không trở nên quá lớn, từ đó cải thiện hiệu quả hoạt động tổng thể của hệ thống.
Khi sử dụng giá trị âmmua thẻ trực tuyến, điều này cho thấy rằng kích thước của ziplist trong mỗi nút quicklist sẽ được giới hạn theo số byte đã sử dụng. Ở chế độ này, giá trị chỉ có thể nằm trong khoảng từ -1 đến -5, và ý nghĩa cụ thể của từng giá trị như sau:
Ngoài rabầu cua, mục tiêu thiết kế của list là có thể lưu trữ các danh sách dữ liệu dài một cách hiệu quả. Ví dụ, trong hướng dẫn được cung cấp trên trang web chính thức của Redis, bạn sẽ thấy: ... (Trong trường hợp này, tôi đã thêm một chút nội dung để làm phong phú câu trả lời nhưng vẫn giữ nguyên ý nghĩa gốc. Tôi cũng thay thế tất cả các từ không phải tiếng Việt bằng cách sử dụng từ ngữ phù hợp trong tiếng Việt.) Writing a simple Twitter clone with PHP and Redis bầu cua, tức là sử dụng list để lưu trữ dữ liệu timeline giống như Twitter.
Khi danh sách trở nên dàibắn cá săn thưởng, dữ liệu ở hai đầu danh sách thường có xu hướng được truy cập nhiều hơn so với những phần ở giữa, mà việc truy cập vào giữa danh sách không chỉ ít phổ biến mà còn gây ra hiệu suất thấp hơn. Nếu ứng dụng của bạn có đặc điểm này, thì danh sách (list) cũng cung cấp một tùy chọn để nén các nút ở giữa, từ đó giúp tối ưu hóa thêm về mặt tài nguyên bộ nhớ. Trong Redis, tham số cấu hình liên quan đến vấn đề này cho phép người dùng điều chỉnh cách danh sách xử lý dữ liệu dựa trên mức độ truy cập và hiệu suất mong muốn.
list-compress-depth
Là để hoàn thành việc thiết lập này.
list-compress-depth 0
Tham số này thể hiện số lượng nút ở hai đầu của quicklist mà không bị nén. Lưu ý rằng số lượng nút này đề cập đến các nút trong danh sách liên kết hai chiều của quicklistbầu cua, chứ không phải số lượng mục dữ liệ Thực tế, khi một nút quicklist được nén, toàn bộ ziplist bên trong nó sẽ bị nén hoàn toàn.
Tham số
list-compress-depth
Ý nghĩa giá trị của nó như sau:
Vì 0 là một giá trị đặc biệtmua thẻ trực tuyến, có thể dễ dàng nhận thấy rằng nút đầu tiên và nút cuối cùng của danh sách quicklist luôn không bị nén, nhằm tạo điều kiện cho việc truy xuất nhanh chóng tại hai đầu của danh sách. Điều này giúp tối ưu hóa hiệu suất khi thao tác với các phần tử ở cả hai extremities (cạnh ngoài cùng) của cấu trúc dữ liệu.
Thuật toán nén nội bộ của quicklist trong Redis sử dụng LZF —— Một thuật toán nén không mất dữ liệu.
Định nghĩa cấu trúc dữ liệu quicklist có thể tìm thấ h:
typedef
struct
quicklistNode
{
struct
quicklistNode
*
prev
;
struct
quicklistNode
*
next
;
unsigned
char
*
zl
;
unsigned
int
sz
;
/* ziplist size in bytes */
unsigned
int
count
:
16
;
/* count of items in ziplist */
unsigned
int
encoding
:
2
;
/* RAW==1 or LZF==2 */
unsigned
int
container
:
2
;
/* NONE==1 or ZIPLIST==2 */
unsigned
int
recompress
:
1
;
/* was this node previous compressed? */
unsigned
int
attempted_compress
:
1
;
/* node can't compress; too small */
unsigned
int
extra
:
10
;
/* more bits to steal for future usage */
}
quicklistNode
;
typedef
struct
quicklistLZF
{
unsigned
int
sz
;
/* LZF size in bytes*/
char
compressed
[];
}
quicklistLZF
;
typedef
struct
quicklist
{
quicklistNode
*
head
;
quicklistNode
*
tail
;
unsigned
long
count
;
/* total count of all entries in all ziplists */
unsigned
int
len
;
/* number of quicklistNodes */
int
fill
:
16
;
/* fill factor for individual nodes */
unsigned
int
compress
:
16
;
/* depth of end nodes not to compress;0=off */
}
quicklist
;
Cấu trúc quicklistNode đại diện cho một nút trong quicklistbắn cá săn thưởng, với ý nghĩa của từng trường dữ liệu như sau:
zlbytes
,
zltail
,
zllen
,
zlend
Bạn có thể tương tác với từng mục dữ liệu. Tuy nhiênbầu cua, cần lưu ý rằng: nếu ziplist đã bị nén, giá trị của sz vẫn sẽ là kích thước của ziplist trước khi bị nén. Điều này có nghĩa là giá trị sz phản ánh kích thước gốc của ziplist, ngay cả khi nó hiện đang ở trạng thái nén.Cấu trúc quicklistLZF biểu diễn một ziplist đã được nén. Trong đó:
Cấu trúc thực sự biểu diễn quicklist là struct cùng tên quicklist:
list-max-ziplist-size
Giá trị của tham số.
list-compress-depth
Giá trị của tham số.
Hình ảnh phía trên là một ví dụ về cấu trúc củ Trong hình minh họa nàymua thẻ trực tuyến, các thông số cấu hình liên quan đến kích thước ziplist và độ sâu nén của các nút như sau:
list-max-ziplist-size 3
list-compress-depth 2
Những điểm cần chú ý trong ví dụ này là:
push
Một quá trình đọc: Quá trình thứ
pop
Tình trạng sau khi thực hiện thao tác.
Bây giờ chúng ta hãy cùng nhau tính toán sơ bộ xem liệu 16bit trong trường count của cấu trúc quicklistNode có đủ để sử dụng hay không. Trong thực tếmua thẻ trực tuyến, việc phân bổ 16bit cho trường count có thể là một lựa chọn cân nhắc giữa hiệu suất và phạm vi giá trị. Nếu quicklistNode được thiết kế để lưu trữ một số lượng lớn nút, thì 16bit có thể không đủ để biểu diễn số lượng phần tử tối đa mà quicklistNode có thể quản lý. Tuy nhiên, nếu phạm vi ứng dụng chỉ yêu cầu một lượng dữ liệu vừa phải, thì điều này hoàn toàn khả thi. Chúng ta cần xem xét thêm các yếu tố như kích thước bộ nhớ trung bình của mỗi nút, tần suất thay đổi trong danh sách liên kết, và cách mà quicklistNode sẽ tương tác với hệ thống. Điều này giúp đảm bảo rằng việc sử dụng 16bit cho count là hợp lý và tối ưu.
Chúng ta đã biết rằng kích thước ziplist bị giới hạn bởi
list-max-ziplist-size
Tham số. Có hai trường hợp dựa trên giá trị dương và âm:
list-max-ziplist-size
Các tham số được lưu trữ trong trường fill của cấu trú Trường fill có kích thước 16 bitbắn cá săn thưởng, do đó các giá trị mà nó có thể biểu diễn đều có thể được biểu thị bằng 16 bit. Điều này cho phép quicklist tối ưu hóa việc quản lý bộ nhớ và tăng cường hiệu suất khi xử lý dữ liệu với phạm vi giá trị lớn nhưng vẫn giữ được độ gọn nhẹ trong cấu trúc.
prevrawlen
bắn cá săn thưởng, trường hợp 1 byte của
data
(
len
Trường và
data
Được hợp nhất; xem thêm
Bài trước
Vì vậybắn cá săn thưởng, số lượng mục dữ liệu trong ziplist sẽ không vượt quá 32K, và việc sử dụng 16 bit để biểu diễn là đủ. Ngoài ra, việc giới hạn này cũng giúp tối ưu hóa không gian lưu trữ, đảm bảo hiệu suất cao hơn cho các hoạt động xử lý dữ liệu liên quan đến ziplist.Trên thực tếmua thẻ trực tuyến, trong việc triển khai hiện tại của quicklist, kích thước của ziplist còn bị giới hạn bởi các yếu tố khác và sẽ không bao giờ đạt đến giá trị tối đa mà chúng ta đang phân tích ở đây. Điều này có nghĩa là dù bạn có thêm nhiều phần tử vào ziplist, nó vẫn sẽ tự động điều chỉnh để tuân theo những giới hạn riêng biệt, đảm bảo hiệu suất và khả năng hoạt động ổn định.
Bây giờ hãy chuyển sang giai đoạn phân tích mã nguồn.
Khi chúng ta sử dụng
lpush
Hai hàm callback này. Thực tếmua thẻ trực tuyến, cách mô tả này vẫn còn khá
rpush
Lệnh chèn dữ liệu lần đầu tiên vào một list chưa tồn tạibắn cá săn thưởng, Redis sẽ gọi
quicklistCreate
Giao diện để tạo một quicklist rỗng.
quicklist
*
quicklistCreate
(
void
)
{
struct
quicklist
*
quicklist
;
quicklist
=
zmalloc
(
sizeof
(
*
quicklist
));
quicklist
->
head
=
quicklist
->
tail
=
NULL
;
quicklist
->
len
=
0
;
quicklist
->
count
=
0
;
quicklist
->
compress
=
0
;
quicklist
->
fill
=
-
2
;
return
quicklist
;
}
Trong nhiều cuốn sách hướng dẫn về cấu trúc dữ liệumua thẻ trực tuyến, khi triển khai danh sách liên kết hai chiều, người ta thường thêm vào một nút đầu trống để làm cho việc chèn và xóa trở nên thuận tiện hơn. Điều này xuất phát từ thực tế rằng việc có một nút đầu đặc biệt giúp tránh các trường hợp viền bờ phức tạp khi thao tác với danh sách. Khi có một nút đầu trống như vậy, các hoạt động trên danh sách liên kết sẽ được quản lý dễ dàng hơn mà không cần phải kiểm tra xem phần tử hiện tại có phải là phần tử đầu tiên hay không. Điều này không chỉ giúp tiết kiệm thời gian lập trình mà còn giảm thiểu lỗi tiềm ẩn trong quá trình xử lý. Ngoài ra, cách thiết kế này cũng giúp mã nguồn trở nên sạch hơn và dễ bảo trì hơn vì mọi thao tác đều được thống nhất theo cùng một quy tắc. Từ quan điểm của lập trình viên, việc thêm nút đầu trống không chỉ là một giải pháp kỹ thuật mà còn là một chiến lược giúp tối ưu hóa hiệu suất và độ tin cậy của chương trình. Với sự hỗ trợ của nút này, việc xử lý danh sách liên kết trở nên đơn giản hơn rất nhiều, đặc biệt khi cần thực hiện các thao tác phức tạp như chèn hoặc xoá ở bất kỳ vị trí nào trong danh sách.
quicklistCreate
Mã nguồn cho thấybầu cua, quicklist là một danh sách liên kết hai chiều không có nút đầu thừa (tất cả đều được khởi tạo thành NULL).
head
Một quá trình đọc: Quá trình thứ
tail
Thao tác push quicklist
Dù chèn dữ liệu vào đầu hay cuốimua thẻ trực tuyến, đều bao gồm hai trường hợp:
quicklistPush
Nếu kích thước ziplist trên nút đầu (hoặc cuối) không vượt quá giới hạn (tức là
void
quicklistPush
(
quicklist
*
quicklist
,
void
*
value
,
const
size_t
sz
,
int
where
)
{
if
(
where
==
QUICKLIST_HEAD
)
{
quicklistPushHead
(
quicklist
,
value
,
sz
);
}
else
if
(
where
==
QUICKLIST_TAIL
)
{
quicklistPushTail
(
quicklist
,
value
,
sz
);
}
}
/* Add new entry to head node of quicklist.
*
* Returns 0 if used existing head.
* Returns 1 if new head created. */
int
quicklistPushHead
(
quicklist
*
quicklist
,
void
*
value
,
size_t
sz
)
{
quicklistNode
*
orig_head
=
quicklist
->
head
;
if
(
likely
(
_quicklistNodeAllowInsert
(
quicklist
->
head
,
quicklist
->
fill
,
sz
)))
{
quicklist
->
head
->
zl
=
ziplistPush
(
quicklist
->
head
->
zl
,
value
,
sz
,
ZIPLIST_HEAD
);
quicklistNodeUpdateSz
(
quicklist
->
head
);
}
else
{
quicklistNode
*
node
=
quicklistCreateNode
();
node
->
zl
=
ziplistPush
(
ziplistNew
(),
value
,
sz
,
ZIPLIST_HEAD
);
quicklistNodeUpdateSz
(
node
);
_quicklistInsertNodeBefore
(
quicklist
,
quicklist
->
head
,
node
);
}
quicklist
->
count
++
;
quicklist
->
head
->
count
++
;
return
(
orig_head
!=
quicklist
->
head
);
}
/* Add new entry to tail node of quicklist.
*
* Returns 0 if used existing tail.
* Returns 1 if new tail created. */
int
quicklistPushTail
(
quicklist
*
quicklist
,
void
*
value
,
size_t
sz
)
{
quicklistNode
*
orig_tail
=
quicklist
->
tail
;
if
(
likely
(
_quicklistNodeAllowInsert
(
quicklist
->
tail
,
quicklist
->
fill
,
sz
)))
{
quicklist
->
tail
->
zl
=
ziplistPush
(
quicklist
->
tail
->
zl
,
value
,
sz
,
ZIPLIST_TAIL
);
quicklistNodeUpdateSz
(
quicklist
->
tail
);
}
else
{
quicklistNode
*
node
=
quicklistCreateNode
();
node
->
zl
=
ziplistPush
(
ziplistNew
(),
value
,
sz
,
ZIPLIST_TAIL
);
quicklistNodeUpdateSz
(
node
);
_quicklistInsertNodeAfter
(
quicklist
,
quicklist
->
tail
,
node
);
}
quicklist
->
count
++
;
quicklist
->
tail
->
count
++
;
return
(
orig_tail
!=
quicklist
->
tail
);
}
Trả về 1)bầu cua, thì dữ liệu mới sẽ được chèn trực tiếp vào ziplist (gọi
_quicklistNodeAllowInsert
Cấu hình để nén các nút bên trong. Việc triển khai khá phức tạpmua thẻ trực tuyến, chúng tôi sẽ không thảo luận chi tiết ở đây.
ziplistPush
)。
_quicklistInsertNodeAfter
)。
Nên là 43; ngược lạibắn cá săn thưởng, nếu chúng ta cho rằng
_quicklistInsertNodeAfter
Các thao tác khác của quicklist
list-compress-depth
Thao tác pop quicklist được thực hiện bằng cách gọi
Các thao tác của quicklist khá nhiều và các chi tiết thực hiện cũng tương đối phức tạpmua thẻ trực tuyến, vì vậy ở đây chúng ta sẽ không đi sâu phân tích mã nguồn nữa. Thay vào đó, chúng tôi sẽ giới thiệu sơ lược về một số thao tác quan trọng.
Được sử dụng để thiết lập tham số cấu hình kích thước ziplist (
quicklistPopCustom
Nếu kích thước ziplist trên nút đầu (hoặc cuối) không vượt quá giới hạn (tức là
quicklistPopCustom
Quá trình thực hiện cơ bản là ngược lại so vớ Đầu tiênbầu cua, bạn cần xóa mục dữ liệu tương ứng từ ziplist của nút đầu hoặc nút cuối. Nếu sau khi xóa mà ziplist trở nên trống rỗng, thì nút đầu hoặc nút cuối đó cũng cần bị xóa đi. Sau khi xóa, có thể còn phát sinh vấn đề liên quan đến việc giải nén các nút bên trong.
) và tham số cấu hình độ sâu nén nút (
quicklistInsertAfter
Một quá trình đọc: Quá trình thứ
quicklistInsertBefore
Bạn có thể chèn các mục dữ liệu ngay sau hoặc ngay trước vị trí được chỉ định. Hoạt động chèn dữ liệu tại bất kỳ vị trí nào được chỉ định này khá phức tạpmua thẻ trực tuyến, với nhiều nhánh logic khác nhau cần được xử lý. Trong thực tế, việc thực hiện thao tác này yêu cầu lập trình viên phải cẩn trọng và chi tiết để đảm bảo rằng mọi trường hợp đặc biệt đều được tính đến. Ví dụ, nếu vị trí cần chèn nằm ở đầu danh sách, giữa danh sách hay gần cuối danh sách sẽ đòi hỏi cách tiếp cận hoàn toàn khác nhau. Hơn nữa, khi danh sách đã đạt đến giới hạn dung lượng, hệ thống cần phải kiểm tra điều kiện mở rộng bộ nhớ hoặc thông báo lỗi cho người dùng. Điều này không chỉ liên quan đến việc di chuyển các phần tử trong cấu trúc dữ liệu mà còn cần quản lý hiệu quả tài nguyên hệ thống, giúp duy trì sự ổn định và hiệu suất tối ưu của ứng dụng.
quicklistSetOptions
) và tham số cấu hình độ sâu nén nút (
list-max-ziplist-size
list-compress-depth
Mã code khá đơn giảnmua thẻ trực tuyến, chỉ cần gán các giá trị tương ứng lần lượt cho trường fill và compress trong cấu trú Bên cạnh đó, đoạn mã này cũng đảm bảo tính linh hoạt khi có thể điều chỉnh các thông số liên quan đến việc nén dữ liệu một cách dễ dàng mà không làm thay đổi toàn bộ cấu trúc ban đầu.
Bài viết tiếp theo của chúng tôi sẽ đề cập đến cấu trúc dữ liệu skiplist và cách nó hỗ trợ cho kiểu dữ liệu Redis là sorted setmua thẻ trực tuyến, hãy cùng đón chờ nhé.