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.

XADD sensor-1234 * temperature 98.7
1538319053569-0

XADD syntax is:

XADD key ID field value [field2 value2 ...]

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.

XADD sensor-1234 1538319053569-1 temperature 98.8
1538319053569-1

The ID must always be greater than the previous one. Equal or smaller IDs raise an error.

Entry count: XLEN

XLEN sensor-1234
(integer) 2

More precisely, it returns the number of IDs.

Query data: XRANGE

XRANGE sensor-1234 - +
1) 1) 1538319053569-0
    2) 1) "temperature"
        2) "98.7"
2) 1) 1538319053569-1
    2) 1) "temperature"
        2) "98.8"

XRANGE syntax is:

XRANGE key start end [COUNT count]

key=sensor-1234, start=-, end=+.
COUNT limits how many entries are returned.
start and end can be specific IDs.

XRANGE key 1538319053569 1538319053569

To read newest entries first, use XREVRANGE.

XREVRANGE key + -

Read data: XREAD

XREAD count 1 STREAMS sensor-1234 1538322045065-0
1) 1) "sensor-1234"
    2) 1) 1) 1538322045065-1
        2) 1) "temperature"
            2) "98.8"

XREAD syntax is:

XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...]
  • 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.
XREAD block 5000 STREAMS sensor-1234 $

Delete data: XDEL, XTRIM

XDEL

XDEL sensor-1234 1538322045065-0
(integer) 1

XDEL syntax is:

XDEL key ID

XTRIM

If sensor-1234 has 100 entries, this deletes the oldest 90 and keeps the latest 10.

XTRIM sensor-1234 maxlen 10

XTRIM syntax is:

XTRIM key MAXLEN [~] count

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

XGROUP CREATE sensor-1234 ConsumerGroup $

Insert test data

XADD sensor-1234 * temperature 100
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

XREADGROUP GROUP ConsumerGroup Consumer-A count 1 STREAMS sensor-1234 >
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

XPENDING sensor-1234 ConsumerGroup
1) (integer) 2
2) 1538568726521-0
3) 1538568728545-0
4) 1) 1) "Consumer-A"
    2) "2"

Acknowledge processing: XACK

XACK sensor-1234 ConsumerGroup 1538568726521-0
(integer) 1

Check pending entries again

XPENDING sensor-1234 ConsumerGroup
1) (integer) 1
2) 1538568728545-0
3) 1538568728545-0
4) 1) 1) "Consumer-A"
    2) "1"

Pending idle time: XINFO CONSUMERS

XINFO CONSUMERS sensor-1234 ConsumerGroup
1) 1) name
    2) "Consumer-A"
    3) pending
    4) (integer) 1
    5) idle
    6) (integer) 31963

Claim pending entries for another consumer: XCLAIM

XCLAIM sensor-1234 ConsumerGroup Consumer-B 30000 1538568728545-0
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:

XCLAIM key group consumer min-idle-time ID

min-idle-time is in milliseconds.
Then keep reading and processing.

XREADGROUP GROUP ConsumerGroup Consumer-B COUNT 1 STREAMS sensor-1234 >
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-1 -> Consumer-A
Data-2 -> Consumer-B
Data-3 -> Consumer-C
Data-4 -> Consumer-A
Data-5 -> Consumer-B
Data-6 -> Consumer-C

STREAMS command list

CommandsVersionSyntaxDescription
XADD5.0.0key ID field string [field string ...]
XLEN5.0.0key
XRANGE5.0.0key start end [COUNT count]
XREVRANGE 5.0.0key end start [COUNT count]
XREAD5.0.0[COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...]
XDEL5.0.0key ID [ID ...]
XTRIM5.0.0key MAXLEN [~] count
XGROUP5.0.0[CREATE key group id-or-$] [DESTROY key group] [DELCONSUMER key group consumer] [SETID key group id-or-$]
XREADGROUP5.0.0GROUP group consumer [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...]
XACK5.0.0key group ID [ID ...]
XPENDING5.0.0key group [start end count] [consumer]
XCLAIM5.0.0key group consumer min-idle-time ID [ID ...] [IDLE ms] [TIME ms-unix-time] [RETRYCOUNT count] [FORCE] [JUSTID]
XAUTOCLAIM6.2.0key 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 >>

Email 답글이 올라오면 이메일로 알려드리겠습니다.