incr
usage
incr Key, you can increment the key value atom by 1 and return the new value corresponding to the key after the increment operation. If the specified key does not exist, its value is set to 0 before the incr operation is performed.
/* Before testing, clear the current database all key*/
127.0.0.1:6379> flushdb
OK
/* No key*/
127.0.0.1:6379> keys *
(empty List or set)
/* Use incr a nonexistent key with a return of 1 (if the specified key does not exist, the value is set to 0 before the incr operation is performed, and the value after the increment is returned 1) */
127.0.0.1:6379 > incr incrkey
(integer) 1
127.0.0.1:6379> get Incrkey
"1"/
* Auto Increment 1, return the added value 2*/
127.0.0.1:6379> incr incrkey
(integer) 2
127.0.0.1:6379> get Incrkey
"2"
1
2
3
4
5
6
7
8
9
ten
each
16
Use Scenario 1-counter
For example: A web app, we want to record the number of times each user visits this site each day. You can use the ID of this user and the date of the same day to join a key, each visit only with INCR to the key operation, so that the user access to the site number of the day. For example, the user ID is 9eda3e419e6eadb99293f5c9105816c93a0ca760, today is 20161015, you can use INCR 9eda3e419e6eadb99293f5c9105816c93a0ca760 : 20161015 to count the number of visits that the user had on the day of 2016-10-15.
The expansion of this scenario: count the number of times the user has visited within a certain time range, and can be combined with incr, expire to achieve the goal. Usage Scenario 2-Limit access count (i)
Let's say we have this requirement: Each API interface can not access more than 10 times per second for each IP.
We can set the key for IP: timestamp (to seconds), and the following pseudo code display:
FUNCTION limit_access_count (IP)
currsecond = Current_unix_time ()
keyName = ip+ ":" +currsecond
currentcnt = GET (keyName)
IF currentcnt! = NULL and currentcnt > ten then
ERROR "too many accesses in one second"
ELSE MULTI/
* such as 10 .192.168.27 at 2016-10-15 15:20:19 when the number of visits is less than 10, has been self-increment *
/INCR (keyname,1)/
* Counters each increment when the time is set to 10 seconds of expiration, so that in the next second, Redis automatically deletes counters from the previous second.
* key 10.192.168.27:2016-10-15 15:20:19 will be deleted after 2016-10-15 15:20:29 *
/EXPIRE (keyname,10)
EXEC
do_job ()
END
1
2
3
4
5
6
7
8
9
11
17
Usage Scenario 2-Limit access count (ii)
The previous example is that each IP generates a key every second. In this case, we will only generate one key for an IP, but we need to pay attention to the appearance of race condition in actual use.
The specific idea is that you set the expiration time to 1 seconds from the first request. If the number of requests exceeds 10 in 1 seconds, an error message is indicated. By the next second, the counter will start counting again after 0.
FUNCTION limit_access_count (IP)
keyName = IP
currentcnt = GET (keyName)
IF currentcnt! = NULL and Currentcnt & Gt Ten then
ERROR "too many accesses in one second"
ELSE
MULTI/
* For example, 10.192.168.27 at 2016-10-15 15:20:19 when the number of visits was less than 10, has been self-increasing * *
currentcnt = INCR (IP)
IF currentcnt = = 1
then/* counters are set to expire 1 seconds each time they are incremented, only set the time-out to 1 seconds on first access
* key 10.192.168.27:2016-10-15 15:20:19 will be removed after 2016-10-15 15:20:20
*
/EXPIRE (keyname,1)
END
EXEC
do_job ()
END
1
2
3
4
5
6
7
8
9
ten
14
18
dealing with race conditions : using LUA scripts.
In the previous example, if the use of INCR, not successfully executed expire, will cause the IP key caused a memory leak, know the next time the same IP sent the same request come over. The logic of possible race conditions can be placed in a LUA script and then resolved with eval (requires REDIS2.6 version above)
/*lua script *
/local currentcnt
currentcnt = Redis.call ("incr", keys[1])
if Tonumber (currentcnt) = = 1
Then Redis.call ("expire", keys[1],1)
end
1
2
3
4
5
6
Getset
getset Key value sets the value to key, but returns the original value of key. If key exists but the corresponding value is not a string, an error is returned. Nil will be returned if the previous key does not exist.
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> keys *
(empty list or set)
/use INCR to implement counter self-increment, Use Getset to reset to 0/
127.0.0.1:6379> incr testKey
(integer) 1
127.0.0.1:6379>
incr TestKey ( Integer) 2
127.0.0.1:6379> getset testKey 0
"2"
127.0.0.1:6379> get TestKey
"0"
/key does not exist return nil/
127.0.0.1:6379> getset TestKey2 0
(nil) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17