概述

我的项目地址:https://github.com/snower/slock

何为状态与原子操作数据库?区别于redis次要用于保留数据,可在多节点多零碎间高效统同步数据,slock则是设计为只用于保留同步状态,简直不能携带数据,高性能的异步二进制协定也保障了在状态达成时高效的被动触发期待零碎。区别于redis被动查看的过期工夫,slock的期待超时工夫及锁定过期工夫都是准确被动触发的。多核反对、更简略的系统结构也保障了其领有远超redis的性能及延时,这也更合乎状态同步需要中更高性能更低延时的需要。

秒杀为何难做?其问题就是咱们须要在很短时间内实现大量的有效申请中夹杂仅很少的无效申请解决,进一步简化就是须要实现超高并发下海量申请间的状态同步的过程,slock高QPS能够疾速解决过滤大量有效申请的问题,高性能的原子操作又能够很好的解决抢库存的逻辑。

随着nodejs的应用,异步IO相干框架也越来越成熟,应用也越来越不便,多线程同步IO模式下,某些场景很多时候咱们须要转化为队列解决而后再推送后果,但异步IO就齐全不须要这么简单,间接加分布式锁期待可用就行,整个过程齐全回到了单机多线程编程的逻辑,更简略也更容易了解和保护了,比方下单申请须要操作很多,在高并发下可能须要发送到队列中解决实现再推送后果,但用异步IO的加分布式锁话,认真看异步IO加锁其实又组成了一个更大的分布式队列,大大简化了实现步骤。

个性

  • 超高性能,在Intel i5-4590上超过200万QPS
  • 高性能二进制异步协定简略稳固牢靠,也可用redis同步文本协定
  • 多核多线程反对
  • 4级AOF长久化

    • 不长久化间接返回
    • 超过过期工夫百分比工夫后长久化后返回
    • 超过AOF工夫长久化后返回
    • 立即异步长久化后返回
    • 需整个集群沉闷节点都胜利并长久化后返回
  • 高可用集群模式,主动迁徙、主动代理
  • 准确到毫秒、秒、分钟超时、过期工夫,可独自订阅超时、过期工夫
  • 屡次锁定反对,重入锁定反对
  • 遗嘱命令

场景示例

分布式锁

整个协定只有中间指令,Lock和Unlock,分布式锁也即是最罕用场景,和redis实现分布式锁区别除了性能更好延时也更低外,期待超时及锁定超时过期工夫时准确被动触发的,所以有wait机制,redis实现的分布式锁个别则须要client被动延时重试来查看。

package main;import io.github.snower.jaslock.Client;import io.github.snower.jaslock.Event;import io.github.snower.jaslock.Lock;import io.github.snower.jaslock.ReplsetClient;import io.github.snower.jaslock.exceptions.SlockException;import java.io.IOException;import java.nio.charset.StandardCharsets;public class App {    public static void main(String[] args) {        ReplsetClient replsetClient = new ReplsetClient(new String[]{"172.27.214.150:5658"});        try {            replsetClient.open();            Lock lock = replsetClient.newLock("test".getBytes(StandardCharsets.UTF_8), 5, 5);            lock.acquire();            lock.release();        } catch (SlockException e) {            e.printStackTrace();        } finally {            replsetClient.close();        }    }}

nginx & openresty限流

openresty应用此服务实现限流能够很不便的实现跨节点,同时因为应用高性能异步二进制协定,每个work只须要一个和server的连贯,高并发下不会产生外部连贯耗尽的问题,server主节点变更的时候work可主动应用新可用主节点,实现高可用。

最大并发数限流

每个key能够设置最大锁定次数,应用该逻辑能够十分不便的实现最大并发限流。

lua_package_path "lib/resty/slock.lua;";init_worker_by_lua_block {        local slock = require("slock")        slock:connect("lock1", "127.0.0.1", 5658)}server {    listen 80;    location /flow/maxconcurrent {          access_by_lua_block {                  local slock = require("slock")                  local client = slock:get("lock1")                  local flow_key = "flow:maxconcurrent"                  local args = ngx.req.get_uri_args()                  for key, val in pairs(args) do                          if key == "flow_key" then                                  flow_key = val                          end                  end                  local lock = client:newMaxConcurrentFlow(flow_key, 10, 5, 60)                  local ok, err = lock:acquire()                  if not ok then                          ngx.say("acquire error:" .. err)                          ngx.exit(ngx.HTTP_OK)                  else                          ngx.ctx.lock1 = lock                  end          }          echo "hello world";          log_by_lua_block {                  local lock = ngx.ctx.lock1                  if lock ~= nil then                          local ok, err = lock:release()                          if not ok then                                  ngx.log(ngx.ERR, "slock release error:" .. err)                          end                  end          }    }}

令牌桶限流

每个key能够设置最大锁定次数,并设置为在令牌到期时过期,即可实现令牌桶限流,应用毫秒级过期工夫的时候也能够从此形式来实现削峰均衡流量。

lua_package_path "lib/resty/?.lua;";init_worker_by_lua_block {        local slock = require("slock")        slock:connect("lock1", "127.0.0.1", 5658)}server {    listen 80;    location /flow/tokenbucket {                access_by_lua_block {                        local slock = require("slock")                        local client = slock:get("lock1")                        local flow_key = "flow:tokenbucket"                        local args = ngx.req.get_uri_args()                        for key, val in pairs(args) do                                if key == "flow_key" then                                        flow_key = val                                end                        end                        local lock = client:newTokenBucketFlow(flow_key, 10, 5, 60)                        local ok, err = lock:acquire()                        if not ok then                                ngx.say("acquire error:" .. err)                                ngx.exit(ngx.HTTP_OK)                        end                }                echo "hello world";        }}

其它可用场景

  • 分布式Event,一个罕用场景如扫码登录,二维码这边需期待扫码状态。
  • 分布式Semaphore,这个即是更通用的限流,此外也能够用于异步工作后果告诉。
  • 分布式读写锁。
  • 秒杀场景,秒杀场景是典型的申请数很高但无效申请数非常少的场景,原子操作的个性能够很好反对抢库存的逻辑,超高的并发反对也能够很好解决天量有效申请的问题。
  • 异步后果告诉,网页间接实现的性能又须要后盾定时工作执行,此时齐全能够网络也调用异步工作,而后通过分布式Event期待执行实现即可。

以上这些应用场景都能够在openresty实现对外接口,再有外部零碎实现触发即可,openresty的高性能高并发齐全能够很容易的解决很多之前须要用队列须要长连贯推送的需要。