Collect Redis Key TTL and Key sizes
Redis Keys statistics including Key Time-to-Live (TTL) statistics and Key sizes are useful for troubleshooting cache usage and performance, from client side.
Key Time-to-Live (TTL):
TTL may have impact on memory usage and memory available on Redis services.
Data Loss on Redis services may happened unexpectedly due to some issue on backend, but may also happen due to Memory eviction policy, or Time-to-Live (TTL) expired.
Memory eviction policy may remove some keys from Redis service, but only when used capacity (the space used by Redis keys) reach 100% on memory available.
Not having any unexpected issue on Redis backend side or not reaching the maximum memory available, the only reason for having some keys removed from cache is due to TTL value.
- TTL may not be defined at all, and in that case the key remains in the cache forever (persistent)
- TTL can be set while setting a new key
- TTL can be set / re-set later after key creation
TTL is defined in seconds or milliseconds, or with a negative value:
- -1, the key exists but has no expiration (it’s persistent); this happens when the TTL was not defined or it was removed using PERSIST command
- -2, if the key does not exist.
- any other value
Related commands:
- SET key1 value1 EX 60 - defines TTL as 60 seconds
- SET key1 value1 PX 60000 - defines TTL as 60000 milliseconds (60 seconds)
- EXPIRE key1 60 - Set a timeout of 60 seconds on key1
- TTL key1 - returns the current TTL value, in seconds
- PTTL key1 - returns the current TTL value, in milliseconds
- PERSIST key1 removes TTL from that key and make the key persistent
Notes:
- TTL counts down in real time, but Redis expiration is lazy + active, so exact timing isn’t guaranteed to the millisecond.
- A TTL of 0 is basically a race condition, that usually are not seen, it because the key expires immediately.
- EXPIRE key 0 deletes the key right away.
There is no guarantee the deletion happens exactly at expiration time. Redis lazy + active expiration means the key is checked only when someone touches it (lazy), but to avoid memory filling up with expired junk, Redis also runs a background job to periodically scan a subset of keys and delete the expired ones (active). So, some expired keys may survive a bit longer, not accessible anymore but still im memory.
Example Redis lazy:
- at 11:59:00 SET key1 value1 EX 60 - 60 seconds expiration time
- key1 expires at 12:00:00
- no one accesses it until 12:00:05 - when someone try to access key1 at 12:00:05, Redis identify the key1 expired and delete it.
Example Redis active:
-
for the same key1, after 12:00:00. if during the periodically background job Redis scan the subset of keys containing key1, that key1 will be actively deleted.
For that reason, we may see some higher memory usage than the real memory used by active keys in the cache.
For more information about Redis commands, check Redis Inc - Commands
Key Sizes:
Large key value sizes in the cache, may have high impact on Redis performance.
Redis service is designed to 1KB response size, and Microsoft recommends to use up to 100KB on Azure Redis services, to get a better performance.
Redis response size may not be exactly the same as key size, as Response size is the sum of the response from each operation sent to Redis.
While the response size can be the size of only one key requested (like GET), we can see very often response size being a sum of more than one key, as result of multikey operations (like MGET and others).
The scope of this article is the focus on each key size; so, we will not discuss on this article the implications of multikey commands.
By design Redis service is a single thread system per shard, and this is not a Microsoft/Azure limitation but a Redis design feature.
To be very quick on processing requests, Redis is optimized to work and process small keys, and for that is more efficient using a single thread instead of the need of context switching.
In a multi threaded system, context switching happens when the processor stops executing one thread and starts executing another.
When that happens, the OS saves the current thread’s state (registers, program counter, stack pointer, etc.) and restores the state of the next thread.
To save time on that process, Redis service is designed to run in a single thread system.
Due to the single thread nature, all operations sent to Redis service, are waiting in a queue to be processed.
To minimize latency, all keys must remain small so they can be processed efficiently and responses can be transmitted to the client quickly over the network.
For that reason, it's important to understand the key sizes we have on our Redis service, and maintain all keys as small as possible.
Scripts Provided
To help on identifying some specific TTL values and Keys sizes in a Redis cache, two solutions are provided below:
1. Get Key statistics - that scans all cache and return only the amount of Redis keys with:
-
- Number of keys with TTL no set
- Number of keys with TTL higher or equal to a user defined TTL threshold
- Number of keys with TTL lower than a user defined TTL threshold
- Number of keys with value size higher or equal than a user defined Size threshold
- Number of keys with value size lower than a user defined Size threshold
- Total number of keys in the cache.
- It also includes start and end time, and the total time spent on the keys scan.
2. List Key Names - this script returns a list of Redis Keys names, based on parameters provided:
-
- No TTL set, or
- TTL higher or equal to a user defined TTL threshold, or
- TTL lower than to a user defined TTL threshold
- Key value size higher or equal than a user defined Size threshold, or
- Key value size lower than a user defined Size threshold
- Total number of keys in the cache
- It also includes start and end time, and the total time spent on the keys scan.
WARNING:
Due to the need to read all keys in the cache, both solutions can cause high workload on Redis side, specially for high datasets on the cache, with high number of keys.
Both solutions are using LUA script that runs on Redis side, and depending on the amount of keys in the cache, may block all other commands to be processed, while the script is running.
The duration time on the output from each script run, may help to identify the impact of the scripts to run.
Run it carefully and do some tests first on your developing environment, before using in a production.
| 1- Get Key statistics |
To get Redis key statistics, we use Linux Bash shell and Redis-cli tool to run LUA script on Redis side, to get TTL values and sizes from each key.
This solution is very fast, but needs to scan all keys in the cache during the LUA script run.
This may block Redis to process other requests, due to the single-thread nature of Redis service.
The below script scans all cache and return only the amount of Redis keys with:
-
- Number of keys with TTL no set
- Number of keys with TTL higher or equal to a user defined TTL threshold
- Number of keys with TTL lower than a user defined TTL threshold
- Number of keys with value size higher or equal than a user defined Size threshold
- Number of keys with value size lower than a user defined Size threshold
- Total number of keys in the cache.
- It also includes start and end time, and the total time spent on the keys scan.
Output:
========================================================
Scanning number of keys with TTL threshold 100 Seconds, and Key size threshold 500 Bytes
Start time: dd-mm-YY 18:12:15
-----------------------
Total keys scanned: 1227
------------
TTL not set : 2
TTL >= 100 seconds: 1225
TTL < 100 seconds: 0
TTL invalid/error : 0
Non existent key : 0
------------
Keys with Size >= 500 Bytes: 1225
Keys with Size < 500 Bytes: 2
Keys with invalid Size : 0
------------------------
End time: dd-mm-YY 19:12:16
Duration : 0 days 00:00:00.630
========================================================
How to run:
- create the below getKeyStats.sh and getKeyStats.lua files on same folder, on your Linux environment (Ubuntu 20.04.6 LTS used)
- give permissions to run Shell script, with command chmod 700 getKeyStats.sh
- Call the script using the syntax:
./getKeyStats.sh host password [port] [ttl_threshold] [size_threshold]
Script parameters:
- host (mandatory) : the URI for the cache
- password (mandatory) : the Redis access key from the cache
- port (optional - default 10000) : TCP port used to access the cache
- ttl_threshold (optional - default 600 - 10 minutes) : Key TTL threshold (in seconds) to be used on the results (use -1 to 1 to get Keys with no TTL set)
- size_threshold (optional - default 102400 - 100KB) : Key Size threshold to be used on the results
Tested with:
- Ubuntu 20.04.6 LTS
- redis-cli -v
redis-cli 7.4.2 - Redis services:
- Azure Managed Redis Balanced B0 OSSMode
- Azure Cache for Redis Standard C1
getKeyStats.sh
#!/usr/bin/env bash
#============================== LUA script version =================
# Linux Bash Script to get statistics from Redis Keys TTL values and Key value sizes
# It returns the Number of:
# - keys with TTL no set
# - keys with TTL higher or equal to TTL_treshold
# - keys with TTL lower TTL_threshold
# - keys with value size higher or equal than Size_threshold
# - keys with value size lower than Size_threshold
# - total number of keys in the cache.
#-------------------------------------------------------
# WARNING:
# It uses LUA script to run on Redis server side.
# Use it carefully, during low Redis workoads.
# Do your tests first on a Dev environment, before use it on production.
#-------------------------------------------------------
# It requires :
# redis-cli v7 or above
#--------------------------------------------------------
# Usage:
# getRedisTTL.sh <cacheuri> <cacheaccesskey> [<accessport>(10000)] [<ttl_treashold>(600)] [<size_threshold>(102400)]
#========================================================
#------------------------------------------------------
# To use non-ssl port requites to remove --tls parameter from Redis-cli command below
#------------------------------------------------------
# Parameters
REDIS_HOST="${1:?Usage: $0 <host> <password> [port] [ttl_threshold] [Size_Threshold]}"
REDISCLI_AUTH="${2:?Usage: $0 <host> <password> [port] [ttl_threshold] [Size_Threshold]}"
REDIS_PORT="${3:-10000}" # 10000 / 6380 / 6379
REDIS_TTL_THRESHOLD="${4:-600}" # 10 minutes
REDIS_SIZE_THRESHOLD="${5:-102400}" # 100KB
# Port number must be numeric
if ! [[ "$REDIS_PORT" =~ ^[0-9]+$ ]]; then
echo "ERROR: Redis Port must be numeric"
exit 1
fi
# TTL threshold must be numeric
if ! [[ "$REDIS_TTL_THRESHOLD" =~ ^[0-9]+$ ]]; then
echo "ERROR: TTL threshold must be numeric"
exit 1
fi
# Size threshold must be numeric
if ! [[ "$REDIS_SIZE_THRESHOLD" =~ ^[0-9]+$ ]]; then
echo "ERROR: Size threshold must be numeric"
exit 1
fi
echo ""
echo "========================================================"
echo "Scaning number of keys with TTL threshold $REDIS_TTL_THRESHOLD Seconds, and Key size threshold $REDIS_SIZE_THRESHOLD Bytes"
# Start time
start_ts=$(date +%s.%3N)
echo "Start time: $(date "+%d-%m-%Y %H:%M:%S")"
echo "------------------------"
echo ""
# Procesing
result=$(redis-cli \
-h "$REDIS_HOST" \
-a "$REDISCLI_AUTH" \
-p "$REDIS_PORT" \
--tls \
--no-auth-warning \
--raw \
--eval getKeyStats.lua , "$REDIS_TTL_THRESHOLD" "$REDIS_SIZE_THRESHOLD" \
| tr '\n' ' ')
read no_ttl nonexist ttl_high ttl_low ttl_invalid size_high size_low size_nil total <<< "$result"
if [[ $result == ERR* ]]; then
echo "Redis Lua error:"
echo "$result"
else
echo "Total keys scanned: $total"
echo "------------"
echo "TTL not set : $no_ttl"
echo "TTL >= $REDIS_TTL_THRESHOLD seconds: $ttl_high"
echo "TTL < $REDIS_TTL_THRESHOLD seconds: $ttl_low"
echo "TTL invalid/error : $ttl_invalid"
echo "Non existent key : $nonexist"
echo "------------"
echo "Keys with Size >= $REDIS_SIZE_THRESHOLD Bytes: $size_high"
echo "Keys with Size < $REDIS_SIZE_THRESHOLD Bytes: $size_low"
echo "Keys with invalid Size : $size_nil"
fi
echo ""
echo "------------------------"
end_ts=$(date +%s.%3N)
echo "End time: $(date "+%d-%m-%Y %H:%M:%S")"
# Duration - Extract days, hours, minutes, seconds, milliseconds
duration=$(awk "BEGIN {print $end_ts - $start_ts}")
days=$(awk "BEGIN {print int($duration/86400)}")
hours=$(awk "BEGIN {print int(($duration%86400)/3600)}")
minutes=$(awk "BEGIN {print int(($duration%3600)/60)}")
seconds=$(awk "BEGIN {print int($duration%60)}")
milliseconds=$(awk "BEGIN {printf \"%03d\", ($duration - int($duration))*1000}")
echo "Duration : ${days} days $(printf "%02d" "$hours"):$(printf "%02d" "$minutes"):$(printf "%02d" "$seconds").$milliseconds"
echo "========================================================"
getKeyStats.lua
local ttl_threshold = tonumber(ARGV[1])
local size_threshold = tonumber(ARGV[2])
local cursor = "0"
-- Counters
local no_ttl = 0
local nonexist = 0
local ttl_high = 0
local ttl_low = 0
local ttl_invalid = 0
local size_high = 0
local size_low = 0
local size_nil = 0
local total = 0
repeat
local scan = redis.call("SCAN", cursor, "COUNT", 1000)
cursor = scan[1]
local keys = scan[2]
for _, key in ipairs(keys) do
local ttl = redis.call("TTL", key)
local size = redis.call("MEMORY","USAGE", key)
total = total + 1
if ttl == -1 then
no_ttl = no_ttl + 1
elseif ttl == -2 then
nonexist = nonexist + 1
elseif type(ttl) ~= "number" then
ttl_invalid = ttl_invalid + 1
elseif ttl >= ttl_threshold then
ttl_high = ttl_high + 1
else
ttl_low = ttl_low + 1
end
if size == nil then
size_nil = size_nil + 1
elseif size >= size_threshold then
size_high = size_high + 1
else
size_low = size_low + 1
end
end
until cursor == "0"
return {
no_ttl,
nonexist,
ttl_high,
ttl_low,
ttl_invalid,
size_high,
size_low,
size_nil,
total
}
Performance:
Redis service used: Azure Managed Redis - Balanced B0 - OSSMode
Scanning number of keys with TTL threshold 600 Seconds, and Key size threshold 102400 Bytes
Total keys scanned: 46161
TTL not set : 0
TTL >= 600 seconds: 46105
TTL < 600 seconds: 56
TTL invalid/error : 0
Non existent key : 0Keys with Size >= 102400 Bytes: 0
Keys with Size < 102400 Bytes: 46161
Keys with invalid Size : 0Duration : 0 days 00:00:00.602
# ------------------
Redis service used: Azure Cache for Redis - Standard - C1Scanning number of keys with TTL threshold 100 Seconds, and Key size threshold 500 Bytes
Total keys scanned: 1227
TTL not set : 2
TTL >= 100 seconds: 1225
TTL < 100 seconds: 0
TTL invalid/error : 0
Non existent key : 0Keys with Size >= 500 Bytes: 1225
Keys with Size < 500 Bytes: 2
Keys with invalid Size : 0Duration : 0 days 00:00:00.630
# ------------------
WARNING:
The above scripts uses LUA script, that runs on Redis side, and may block you normal workload.
Use it carefully when have a large number of keys in the cache, and during low workload times.
| 2 - List Key Names |
Once we identify some amount of keys in the cache with some specific threshold, we may want to list that key names.
The below script can help on that, and returns a list of Redis Keys names with:
- No TTL set
- TTL higher or equal to a user defined TTL threshold
- TTL lower than to a user defined TTL threshold
- Key value size higher or equal than a user defined Size threshold
- Key value size lower than a user defined Size threshold
- Total number of keys in the cache
- It also includes start and end time, and the total time spent on the keys scan.
Output:
List all key names with TTL above 100 Seconds, and Key size larger 500 Bytes
Start time: dd-mm-YY 18:30:22
------------------------
1) "--------------------------------------"
2) "Key_1787_1022: TTL: 461837 seconds, Size: 1336 Bytes"
(...)
1551) "Key_1173_1022: TTL: 389795 seconds, Size: 1336 Bytes"
1552) "--------------------------------------"
1553) "Scan completed."
1554) "Total of 1550 keys scanned."
1555) "1225 keys found with TTL >= 100 seconds, and size larger than 500 Bytes"
1556) "--------------------------------------"
End time: dd-mm-YY 18:30:22
Duration : 0 days 00:00:00.545
========================================================
How to run:
- create the below listKeys.sh file under some folder, on your Linux environment (Ubuntu 20.04.6 LTS used)
- give permissions to run Shell script, with command chmod 700 listKeys.sh
- Call the script using the syntax:
./listKeys.sh host password [port] [+/-][ttl_threshold] [+/-][size_threshold]
Script parameters:
- host (mandatory) : the URI for the cache
- password (mandatory) : the Redis access key from the cache
- port (optional - default 10000) : TCP port used to access the cache
-
[+/-] (optional) before ttl_threshold: indicates if we want return keys with lower "-", or higher TTL "+" or "" than ttl_threshold
- ttl_threshold (optional - default 600 - 10 minutes) : Key TTL threshold (in seconds) to be used on the results (use -1 to get Keys with no TTL set)
- [+/-] (optional) before size_threshold: indicates if we want return keys with small size "-", or large size "+" or "" than size_threshold
- size_threshold (optional - default 102400 - 100KB) : Key Size threshold to be used on the results
Tips:
-
use ttl_threshold = -1 to return key names with no TTL (ex: /listKeys.sh [port] -1 [+/-][size_Threshold])
-
use ttl_threshold = 0 to return key names with any TTL (ex: /listKeys.sh [port] 0 [+/-][size_Threshold])
- use ttl_threshold = -500 to return key names with TTL below 500 seconds (ex: /listKeys.sh [port] -500 [+/-][size_Threshold])
- use ttl_threshold = 500 to return key names with TTL above or equal to 500 seconds (ex: /listKeys.sh [port] 500 [+/-][size_Threshold])
- use size_threshold = 0 to return key names with any size in the cache (ex: /listKeys.sh [port] [+/-][ttl_threshold] 0)
- use size_threshold = -1000 to return key names with size below 1000 Bytes (ex: /listKeys.sh [port] [+/-][ttl_threshold] -1000)
- use size_threshold = 1000 to return key names with size above or equal to 1000 Bytes (ex: /listKeys.sh [port] [+/-][ttl_threshold] 1000)
- use ttl_threshold = 0 AND size_threshold = 0 to return all key names with any TTL and any size in the cache (ex: /listKeys.sh [port] 0 0)
- use ttl_threshold = -1 AND size_threshold = 0 to return all key names with no TTL and any size in the cache (ex: /listKeys.sh [port] -1 0)
Tested with:
- Ubuntu 20.04.6 LTS
- redis-cli -v
redis-cli 7.4.2 - Redis services:
- Azure Managed Redis Balanced B0 OSSMode
- Azure Cache for Redis Standard C1
listKeys.sh
#!/usr/bin/env bash
set -euo pipefail
#============================== LUA script version =================
# Linux Bash Script to list Redis Keys names
# It returns key names with:
# - No TTL set
# - with TTL higher or equal to TTL_treshold
# - with TTL lower TTL_threshold
# - with value size higher or equal than Size_threshold
# - with value size lower than Size_threshold
# - total number of keys in the cache.
#-------------------------------------------------------
# WARNING:
# It uses LUA script (included on Bash code) to run on Redis server side.
# Use it carefully, during low Redis workoads.
# Do your tests first on a Dev environment, before use it on production.
#-------------------------------------------------------
# It requires :
# redis-cli v7 or above
#--------------------------------------------------------
# Usage:
# listKeys.sh <cacheuri> <cacheaccesskey> [<accessport>(10000)] [+/-][<ttl_treashold>(-1)] [+/-][<size_treashold>(102400)]
#========================================================
#------------------------------------------------------
# Using non-ssl port requires to remove --tls parameter on Redis-cli command below
#------------------------------------------------------
sintax="<redis_host> <password> [redis_port] [+/-][ttl_threshold] [+/-][size_threshold]"
REDIS_HOST="${1:?Usage: $0 $sintax}"
REDISCLI_AUTH="${2:?Usage: $0 $sintax}"
REDIS_PORT="${3:-10000}" # Redis port (10000, 6380, 6379)
KEYTTL_THRESHOLD=${4:-"-1"} # -1, +TTL_threshold, TTL_threashold, -TTL_threshold
KEYSIZE_THRESHOLD="${5:-102400}" # +Size_threshold, Size_threashold, -Size_threshold
# Port number must be numeric
if ! [[ "$REDIS_PORT" =~ ^[0-9]+$ ]]; then
echo "ERROR: Redis Port must be numeric"
exit 1
fi
# Check if KEYTTL_THRESHOLD is a valid integer
if ! [[ "$KEYTTL_THRESHOLD" =~ ^[-+]?[0-9]+$ ]]; then
echo "Error: ttl_threshold $KEYTTL_THRESHOLD is not an integer"
exit 1
fi
# Check if KEYSIZE_THRESHOLD is a valid integer
if ! [[ "$KEYSIZE_THRESHOLD" =~ ^[-+]?[0-9]+$ ]]; then
echo "Error: Size_threshold $KEYSIZE_THRESHOLD is not an integer"
exit 1
fi
# Check if TTL Threasold is positive (or zero), or negative
if [ "$KEYTTL_THRESHOLD" -ge 0 ]; then
TTLSIGN="+"
else
TTLSIGN="-"
fi
# Check if Size Threshold is positive (or zero), or negative
if [ "$KEYSIZE_THRESHOLD" -ge 0 ]; then
SIZESIGN="+"
size_text="larger"
else
SIZESIGN="-"
size_text="smaler"
fi
# specific with no TTL set
if [ "$KEYTTL_THRESHOLD" -eq -1 ]; then
ttl_text="No TTL set"
fi
if [ "$KEYTTL_THRESHOLD" -ge 0 ]; then
ttl_text="TTL above $KEYTTL_THRESHOLD Seconds"
fi
if [ "$KEYTTL_THRESHOLD" -lt -1 ]; then
ttl_text="TTL below ${KEYTTL_THRESHOLD#[-+]} Seconds"
fi
# remove any sign
KEYTTL_THRESHOLD="${KEYTTL_THRESHOLD#[-+]}"
KEYSIZE_THRESHOLD="${KEYSIZE_THRESHOLD#[-+]}"
echo "========================================================"
echo "List all key names with $ttl_text, and Key size $size_text $KEYSIZE_THRESHOLD Bytes"
# Start time
start_ts=$(date +%s.%3N)
echo "Start time: $(date "+%d-%m-%Y %H:%M:%S")"
echo "------------------------"
echo ""
# Procesing
redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" -a "$REDISCLI_AUTH" --tls --no-auth-warning EVAL "
local cursor = '0'
local ttl_threshold = tonumber(ARGV[1]) -- KEYTTL_THRESHOLD
local ttl_sign = ARGV[2] -- TTLSIGN
local size_threshold = tonumber(ARGV[3]) -- KEYSIZE_THRESHOLD
local size_sign = ARGV[4] -- SIZESIGN
local output = {}
local count = 0
local totalKeys = 0
local strKeyTTL = ''
local strKeySize = ''
-- Scanning keys in the cache
table.insert(output, '--------------------------------------')
repeat
local res = redis.call('SCAN', cursor, 'COUNT', 100)
cursor = res[1]
for _, k in ipairs(res[2]) do
local ttl = redis.call('TTL', k)
local size = redis.call('MEMORY','USAGE', k)
totalKeys = totalKeys + 1
if (size_sign == '+' and size >= size_threshold) or (size_sign == '-' and size < size_threshold) then
-- TTL == -1 → no expiration
if ttl_sign == '-' and ttl_threshold == 1 then
if ttl == -1 then
table.insert(output, k .. ': TTL: -1, Size: ' .. size .. ' Bytes')
count = count + 1
end
-- TTL comparisons (exclude -1 and -2)
else
if ttl >= 0 then
table.insert(output, k .. ': TTL: ' .. ttl .. ' seconds, Size: ' .. size .. ' Bytes')
if ttl_sign == '-' and ttl < ttl_threshold then
count = count + 1
elseif ttl_sign == '+' and ttl >= ttl_threshold then
count = count + 1
end
end
end
end
end
until cursor == '0'
-- Adding summary to output
table.insert(output, '--------------------------------------')
if (size_sign == '+') then
strKeySize = 'larger'
else
strKeySize = 'smaler'
end
strKeySize = 'size ' .. strKeySize .. ' than ' .. size_threshold .. ' Bytes'
if ttl_sign == '-' and ttl_threshold == 1 then
strKeyTTL = 'No TTL'
elseif ttl_sign == '-' then
strKeyTTL = 'TTL < ' .. ttl_threshold .. ' seconds'
elseif ttl_sign == '+' then
strKeyTTL = 'TTL >= ' .. ttl_threshold .. ' seconds'
end
strKeyTTL = ' keys found with ' .. strKeyTTL
table.insert(output, 'Scan completed.')
table.insert(output, 'Total of ' .. totalKeys .. ' keys scanned.')
table.insert(output, count .. strKeyTTL .. ', and ' .. strKeySize)
table.insert(output, '--------------------------------------')
return output
" 0 "$KEYTTL_THRESHOLD" "$TTLSIGN" "$KEYSIZE_THRESHOLD" "$SIZESIGN"
echo " "
end_ts=$(date +%s.%3N)
echo "End time: $(date "+%d-%m-%Y %H:%M:%S")"
# Duration - Extract days, hours, minutes, seconds, milliseconds
duration=$(awk "BEGIN {print $end_ts - $start_ts}")
days=$(awk "BEGIN {print int($duration/86400)}")
hours=$(awk "BEGIN {print int(($duration%86400)/3600)}")
minutes=$(awk "BEGIN {print int(($duration%3600)/60)}")
seconds=$(awk "BEGIN {print int($duration%60)}")
milliseconds=$(awk "BEGIN {printf \"%03d\", ($duration - int($duration))*1000}")
echo "Duration : ${days} days $(printf "%02d" "$hours"):$(printf "%02d" "$minutes"):$(printf "%02d" "$seconds").$milliseconds"
echo "========================================================"
Performance:
This script is much cleaner and more connection-efficient than the previous one, for the same results.
It creates only one connection to Redis service, and all processing is made on Redis side on LUA script.
Despite much more efficient, LUA script may block normal workload on Redis, namely having a large dataset, with high number of keys in the cache.
Redis service used: Azure Managed Redis Balanced B0 OSSMode
# ------------------
Scan completed. Total keys listed: 46005
Duration : 0 days 00:00:01.437# ------------------
Redis service used: Azure Cache for Redis - Standard - C1
Scan completed. Total keys listed: 1225
Duration : 0 days 00:00:00.545# ------------------
WARNING:
The above script uses LUA script, that runs on Redis side, and may block you normal workload.
Use it carefully when have a large number of keys in the cache, and during low workload times.
| References |
- Azure Managed Redis
- Azure Best Practice for Development
- Redis Inc - Commands
- Redis LUA - Lua API reference
- Redis Inc - How Redis expires keys
- Redis CLI
- Bash Script
- xargs man page
- awk man page
I hope this can be useful !!!