streams_intro
STREAMS Introduction
Apply for Redis Developer Course
|
Redis Regular Inspection / Technical Support
|
Redis Enterprise Server
|
|---|
Introduction
Streams
STREAM was added in Redis 5.0 to process log data.
In many industries, data is produced continuously.
It is generated by machines rather than people, in a continuous, high-volume flow.
Another trait is that existing records are not updated; new records are only appended.
We call this kind of data a stream or log.
For example, semiconductor, display, and steel manufacturing lines run many sensors
for temperature, humidity, pressure, vibration, inclination, illuminance, and smoke,
producing data at sub-second intervals.
Plants use this data to analyze product defects, and sometimes to prevent defects in advance.
semiconductor wafer defects
A closer example: monitoring many servers.
You can collect CPU, Memory, Disk I/O, and Network I/O from each server,
show real-time charts, and send alerts.
Redis 5.0 introduced STREAM as a data structure suited to storing and processing this kind of data.
disk vs memory, RDB table vs STREAM
The following sections walk through adding and reading stream data.
Append data: XADD
Add temperature data for sensor-1234.
1538319053569-0
XADD syntax is:
key=sensor-1234, ID=*, field=temperature, value=98.7.
Note ID=*. Passing * lets Redis generate and return the ID.
An ID has two numbers:
<millisecondsTime>-<sequenceNumber>
The first is a millisecond timestamp.
The second increments 1, 2, 3, ... within the same millisecond to avoid duplicates.
sequenceNumber is an 8-byte integer, so there is effectively no limit on entries in the same millisecond.
ID=* uses the time of the server running Redis.
You can also specify an ID yourself.
1538319053569-1
The ID must always be greater than the previous one. Equal or smaller IDs raise an error.
Entry count: XLEN
(integer) 2
More precisely, it returns the number of IDs.
Query data: XRANGE
1) 1) 1538319053569-0
2) 1) "temperature"
2) "98.7"
2) 1) 1538319053569-1
2) 1) "temperature"
2) "98.8"
XRANGE syntax is:
key=sensor-1234, start=-, end=+.
COUNT limits how many entries are returned.
start and end can be specific IDs.
To read newest entries first, use XREVRANGE.
Read data: XREAD
1) 1) "sensor-1234"
2) 1) 1) 1538322045065-1
2) 1) "temperature"
2) "98.8"
XREAD syntax is:
- COUNT is how many entries to read. Omit COUNT to read all matching entries.
- ID reads entries after that ID. Use 0 to start from the first entry.
- BLOCK waits for new data. In that case use the special ID $.
This is similar to BLPOP on lists.
Delete data: XDEL, XTRIM
XDEL
(integer) 1
XDEL syntax is:
XTRIM
If sensor-1234 has 100 entries, this deletes the oldest 90 and keeps the latest 10.
XTRIM syntax is:
The special option ~ means about. If sensor-1234 has 1 million entries, deleting 999,990 of them takes time. While that delete runs, XADD and XREAD cannot proceed. Streams that must handle large volume should not stall like that. ~ deletes only as many entries as can be processed quickly.
Compared with other data types
LIST
Until STREAM existed, LIST was the usual Redis type for stream/log data.
- LPUSH, XADD: similar roles, different speed. LPUSH is O(1) and XADD is O(log(N)). O(1), O(N), O(log(N))
- RPOP, XREAD: RPOP reads and removes. XREAD only reads.
RPOP is O(1) and XREAD is O(log(N)).
If the application fails after RPOP, there is no way to recover the entry.
To read a LIST without removing, use LINDEX.
To read and then remove a STREAM entry like RPOP, use XREAD and XDEL. - LREM, XDEL: LREM is O(N) and XDEL is O(log(N)).
- LTRIM, XTRIM: LTRIM is O(N) and XTRIM is O(log(N)).
- Compare speed: LIST compares string values. STREAM compares numeric IDs, so STREAM compares faster.
- Data: LIST requires the application to parse fields and values.
LIST: "sensor-1234;1538319053569;temperature;98.7"
STREAM keeps fields and values separate in Redis. - Inserting in the middle: possible with LIST, not with STREAM.
Sorted SET
Both types are ordered by score/ID. If you stored stream/log data in a ZSET, you would use timestamp as the score.
- ZADD, XADD: both O(log(N)).
- ZPOPMAX, XREAD: reading the last entry is O(log(N)) for both.
- ZREM, XDEL: both O(log(N)).
- Data: ZSET does not allow duplicate members.
If the same value can arrive twice, you must add a discriminator such as a timestamp.
Example) Score: 1538319053569, Value: "sensor-1234;1538319053569;temperature;98.7" - Inserting in the middle: possible with ZSET, not with STREAM.
HASH
Both have fields. HGETALL does not preserve insertion order, while STREAM keeps the order fields were added.
STREAM features other types do not have
- Redis streams let you read data as a named consumer,
- check whether that consumer processed the data,
- and reassign unprocessed entries to another consumer.
The following shows how to do that.
Create a consumer group: XGROUP
Insert test data
XADD sensor-1234 * temperature 101
XADD sensor-1234 * temperature 102
XADD sensor-1234 * temperature 103
XADD sensor-1234 * temperature 104
XADD sensor-1234 * temperature 105
Read with a consumer group: XREADGROUP
1) 1) "sensor-1234"
2) 1) 1) 1538568726521-0
2) 1) "temperature"
2) "100"
XREADGROUP GROUP ConsumerGroup Consumer-A COUNT 1 STREAMS sensor-1234 >
1) 1) "sensor-1234"
2) 1) 1) 1538568728545-0
2) 1) "temperature"
2) "101"
Check pending entries: XPENDING
1) (integer) 2
2) 1538568726521-0
3) 1538568728545-0
4) 1) 1) "Consumer-A"
2) "2"
Acknowledge processing: XACK
(integer) 1
Check pending entries again
1) (integer) 1
2) 1538568728545-0
3) 1538568728545-0
4) 1) 1) "Consumer-A"
2) "1"
Pending idle time: XINFO CONSUMERS
1) 1) name
2) "Consumer-A"
3) pending
4) (integer) 1
5) idle
6) (integer) 31963
Claim pending entries for another consumer: XCLAIM
1) 1) 1538568728545-0
2) 1) "temperature"
2) "101"
This reassigns only that one entry to another consumer.
After XCLAIM you still need XACK.
Simple XCLAIM syntax:
min-idle-time is in milliseconds.
Then keep reading and processing.
1) 1) "sensor-1234"
2) 1) 1) 1538568731409-0
2) 1) "temperature"
2) "102"
Several consumers on one stream
If one stream has a lot of work and processing is slow,
you can assign several consumers as below.
For example, if 3 entries (Data-1,2,3) arrive per second and each takes 1 second to process,
use 3 consumers (Consumer-A,B,C) in separate applications.
Data-2 -> Consumer-B
Data-3 -> Consumer-C
Data-4 -> Consumer-A
Data-5 -> Consumer-B
Data-6 -> Consumer-C
| Commands | Version | Syntax | Description |
|---|---|---|---|
| XADD | 5.0.0 | key ID field string [field string ...] | |
| XLEN | 5.0.0 | key | |
| XRANGE | 5.0.0 | key start end [COUNT count] | |
| XREVRANGE | 5.0.0 | key end start [COUNT count] | |
| XREAD | 5.0.0 | [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...] | |
| XDEL | 5.0.0 | key ID [ID ...] | |
| XTRIM | 5.0.0 | key MAXLEN [~] count | |
| XGROUP | 5.0.0 | [CREATE key group id-or-$] [DESTROY key group] [DELCONSUMER key group consumer] [SETID key group id-or-$] | |
| XREADGROUP | 5.0.0 | GROUP group consumer [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...] | |
| XACK | 5.0.0 | key group ID [ID ...] | |
| XPENDING | 5.0.0 | key group [start end count] [consumer] | |
| XCLAIM | 5.0.0 | key group consumer min-idle-time ID [ID ...] [IDLE ms] [TIME ms-unix-time] [RETRYCOUNT count] [FORCE] [JUSTID] | |
| XAUTOCLAIM | 6.2.0 | key group consumer min-idle-time start [COUNT count] [JUSTID] | |
| XINFO | 5.0.0 | [CONSUMERS key group] [GROUPS key] [STREAM key] [HELP] |
Total : 14
PDF manual
| << HRANDFIELD | STREAMS Introduction | XADD >> |
|---|
