利用Redis实现SQL伸缩的方法_Redis

这篇文章主要介绍了利用Redis实现SQL伸缩的方法,包括讲到了锁和时间序列等方面来提升传统数据库的性能,需要的朋友可以参考下。

缓解行竞争

我们在Sentry开发的早起采用的是sentry.buffers。 这是一个简单的系统,它允许我们以简单的Last Write Wins策略来实现非常有效的缓冲计数器。 重要的是,我们借助它完全消除了任何形式的耐久性 (这是Sentry工作的一个非常可接受的方式)。

操作非常简单,每当一个更新进来我们就做如下几步:

  • 创建一个绑定到传入实体的哈希键(hash key)
  • 使用HINCRBY使计数器值增加
  • HSET所有的LWW数据(比如 "最后一次见到的")
  • 用当前时间戳ZADD哈希键(hash key)到一个"挂起" set

现在每一个时间刻度 (在Sentry中为10秒钟) 我们要转储(dump)这些缓冲区并且扇出写道(fanout the writes)。 看起来像下面这样:

  • 使用ZRANGE获取所有的key
  • 为每一个挂起的key发起一个作业到RabbitMQ

现在RabbitMQ作业将能够读取和清除哈希表,和“悬而未决”更新已经弹出了一套。有几件事情需要注意:

  • 在下面我们想要只弹出一个设置的数量的例子中我们将使用一组排序(举例来说我们需要那100个旧集合)。
  • 假使我们为了处理一个键值来结束多道排序的作业,这个人会得到no-oped由于另一个已经存在的处理和清空哈希的过程。
  • 该系统能够在许多Redis节点上不断扩展下去仅仅是通过在每个节点上安置把一个'悬置'主键来实现。

我们有了这个处理问题的模型之后,能够确保“大部分情况下”每次在SQL中只有一行能够被马上更新,而这样的处理方式减轻了我们能够预见到的锁问题。考虑到将会处理一个突然产生且所有最终组合在一起进入同一个计数器的数据的场景,这种策略对Sentry用处很多。

速度限制

出于哨兵的局限性,我们必须终结持续的拒绝服务攻击。我们通过限制连接速度来应对这种问题,其中一项是通过Redis支持的。这无疑是在sentry.quotas范围内更直接的实现。

它的逻辑相当直接,如同下面展示的那般:

def incr_and_check_limit(user_id, limit):
 key = '{user_id}:{epoch}'.format(user_id, int(time() / 60)) 

 pipe = redis.pipeline()
 pipe.incr(key)
 pipe.expire(key, 60)
 current_rate, _ = pipe.execute() 

 return int(current_rate) > limit 

我们所阐明的限制速率的方法是 Redis在高速缓存服务上最基本的功能之一:增加空的键字。在高速缓存服务中实现同样的行为可能最终使用这种方法:

def incr_and_check_limit_memcache(user_id, limit):
 key = '{user_id}:{epoch}'.format(user_id, int(time() / 60)) 

 if cache.add(key, 0, 60):
  return False 

 current_rate = cache.incr(key) 

 return current_rate > limit 

事实上我们最终采取这种策略可以使哨兵追踪不同事件的短期数据。在这种情况下,我们通常对用户数据进行排序以便可以在最短的时间内找到最活跃用户的数据。

基本锁

虽然Redis的是可用性不高,我们的用例锁,使其成为工作的好工具。我们没有使用这些在哨兵的核心了,但一个示例用例是,我们希望尽量减少并发性和简单无操作的操作,如果事情似乎是已经在运行。这对于可能需要执行每隔一段时间类似cron任务非常有用,但不具备较强的协调。

在Redis的这样使用SETNX操作是相当简单的:

from contextlib import contextmanagerr = Redis()@contextmanagerdef lock(key, nowait=True):
 while not r.setnx(key, '1'):
  if nowait:
   raise Locked('try again soon!')
  sleep(0.01) 

 # limit lock time to 10 seconds
 r.expire(key, 10) 

 # do something crazy
 yield 

 # explicitly unlock
 r.delete(key) 

而锁()内的哨兵利用的memcached的,但绝对没有理由我们不能在其切换到Redis。
时间序列数据

近来我们创造一个新的机制在Sentry(包含在sentry.tsdb中) 存储时间序列数据。这是受RRD模型启发,特别是Graphite。我们期望一个快速简单的方式存储短期(比如一个月)时间序列数,以便于处理高速写入数据,特别是在极端情况下计算潜在的短期速率。尽管这是第一个模型,我们依旧期望在Redis存储数据,它也是使用计数器的简单范例。

在目前的模型中,我们使用单一的hash map来存储全部时间序列数据。例如,这意味所有数据项在都将同一个哈希键拥有一个数据类型和1秒的生命周期。如下所示:

{ 

  "<type enum>:<epoch>:<shard number>": { 

    "<id>": <count> 

  }} 

因此在这种状况,我们需要追踪事件的数目。事件类型映射到枚举类型"1".该判断的时间是1s,因此我们的处理时间需要以秒计。散列最终看起来是这样的:

 { 

  "1:1399958363:0": { 

    "1": 53, 

    "2": 72, 

  }} 

一个可修改模型可能仅使用简单的键并且仅在存储区上增加一些增量寄存器。

"1:1399958363:0:1": 53 

我们选择哈希映射模型基于以下两个原因:

我们可以将所有的键设为一次性的(这也可能产生负面影响,但是目前为止是稳定的)

大幅压缩键值,这是相当重要的处理

此外,离散的数字键允许我们在将虚拟的离散键值映射到固定数目的键值上,并在此分配单一存储区(我们可以使用64,映射到32个物理结点上)

现在通过使用 Nydus和它的map()(依赖于一个工作区)(),数据查询已经完成。这次操作的代码是相当健壮的,但幸好它并不庞大。

def get_range(self, model, keys, start, end, rollup=None):
 """ To get a range of data for group ID=[1, 2, 3]: Start and end are both inclusive. >>> now = timezone.now() >>> get_keys(tsdb.models.group, [1, 2, 3], >>>   start=now - timedelta(days=1), >>>   end=now) """
 normalize_to_epoch = self.normalize_to_epoch
 normalize_to_rollup = self.normalize_to_rollup
 make_key = self.make_key 

 if rollup is None:
  rollup = self.get_optimal_rollup(start, end) 

 results = []
 timestamp = end
 with self.conn.map() as conn:
  while timestamp >= start:
   real_epoch = normalize_to_epoch(timestamp, rollup)
   norm_epoch = normalize_to_rollup(timestamp, rollup) 

   for key in keys:
    model_key = self.get_model_key(key)
    hash_key = make_key(model, norm_epoch, model_key)
    results.append((real_epoch, key, conn.hget(hash_key, model_key))) 

   timestamp = timestamp - timedelta(seconds=rollup) 

 results_by_key = defaultdict(dict)
 for epoch, key, count in results:
  results_by_key[key][epoch] = int(count or 0) 

 for key, points in results_by_key.iteritems():
  results_by_key[key] = sorted(points.items())
 return dict(results_by_key) 

归结如下:

  • 生成所必须的键。
  • 使用工作区,提取所有连接操作的最小结果集(Nydus负责这些)。
  • 给出结果,并且基于指定的时间间隔内和给定的键值将它们映射到当前的存储区内。

以上就是如何利用Redis实现SQL伸缩的方法,希望对大家的学习有所帮助。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索redis
, sql伸缩
, redis和nosql
redis和nosql的区别
redis设计与实现、redis队列实现秒杀、redis设计与实现 pdf、redis实现消息队列、redis实现分布式锁,以便于您获取更多的相关知识。

时间: 2024-10-12 12:48:33

利用Redis实现SQL伸缩的方法_Redis的相关文章

利用Redis实现SQL伸缩的方法简介_Redis

缓解行竞争 我们在Sentry开发的早起采用的是sentry.buffers. 这是一个简单的系统,它允许我们以简单的Last Write Wins策略来实现非常有效的缓冲计数器. 重要的是,我们借助它完全消除了任何形式的耐久性 (这是Sentry工作的一个非常可接受的方式). 操作非常简单,每当一个更新进来我们就做如下几步:     创建一个绑定到传入实体的哈希键(hash key)     使用HINCRBY使计数器值增加     HSET所有的LWW数据(比如 "最后一次见到的"

从MySQL到Redis的简单数据库迁移方法_Redis

 从mysql搬一个大表到redis中,你会发现在提取.转换或是载入一行数据时,速度慢的让你难以忍受.这里我就要告诉一个让你解脱的小技巧.使用"管道输出"的方式把mysql命令行产生的内容直接传递给redis-cli,以绕过"中间件"的方式使两者在进行数据操作时达到最佳速度. 一个约八百万行数据的mysql表,原本导入到redis中需要90分钟,使用这个方法后,只需要两分钟.不管你信不信,反正我是信了. Mysql到Redis的数据协议 redis-cli命令行工具

redis配置认证密码的方法_Redis

1.通过配置文件进行配置yum方式安装的redis配置文件通常在/etc/redis.conf中,打开配置文件找到 #requirepass foobared 去掉行前的注释,并修改密码为所需的密码,保存文件 requirepass myRedis 重启redis sudo service redis restart #或者 sudo service redis stop sudo redis-server /etc/redis.conf 这个时候尝试登录redis,发现可以登上,但是执行具体命

Redis数据库的安装配置方法_Redis

redis 是一个高性能的key-value数据库. redis的出现,很大程度补偿了memcached这类keyvalue存储的不足,在部 分场合可以对关系数据库起到很好的补充作用.它提供了Python,Ruby,Erlang,PHP客户端,使用很方便.问题是这个项目还很新,可能还不足够稳定,而且没有在实际的一些大型系统应用的实例.此外,缺乏mc中批量get也是比较大的问题,始终批量获取跟多次获取的网络开销是不一样的. 性能测试结果: SET操作每秒钟 110000 次,GET操作每秒钟 81

简单粗暴的Redis数据备份和恢复方法_Redis

示例 目标:把服务器CentOS上的redis数据复制到Mac机上 步骤: 在CentOS上找dump文件位置 vi /etc/redis.conf dbfilename dump.rdb dir /var/lib/redis 说明文件在 /var/lib/redis/dump.rdb 在mac上查找dump文件位置 vi /usr/local/etc/redis.conf dbfilename dump.rdb dir /usr/local/var/db/redis 拷贝服务器上的dump.r

Redis批量删除KEY的方法_Redis

Redis 中有删除单个 Key 的指令 DEL,但好像没有批量删除 Key 的指令,不过我们可以借助 Linux 的 xargs 指令来完成这个动作. 复制代码 代码如下: redis-cli keys "*" | xargs redis-cli del //如果redis-cli没有设置成系统变量,需要指定redis-cli的完整路径 //如:/opt/redis/redis-cli keys "*" | xargs /opt/redis/redis-cli d

Redis数据库中实现分布式锁的方法_Redis

分布式锁是一个在很多环境中非常有用的原语,它是不同进程互斥操作共享资源的唯一方法.有很多的开发库和博客描述如何使用Redis实现DLM(Distributed Lock Manager),但是每个开发库使用不同的方式,而且相比更复杂的设计与实现,很多库使用一些简单低可靠的方式来实现. 这篇文章尝试提供更标准的算法来使用Redis实现分布式锁.我们提出一种算法,叫做Relock,它实现了我们认为比vanilla单一实例方式更安全的DLM(分布式锁管理).我们希望社区分析它并提供反馈,以做为更加复杂

PHPcms利用xss执行sql注入

昨天看见phpcms v9.1.15爆的xss和无权限的sql注入,于是就想测试下利用xss执行sql注入,虽然爆的这个phpcms漏洞还有很多其他的用法!但是,这个注入我没有找到phpcms v9.1.15测试,其他版本都没有测试成功! 于是乎我只有假想下一个极端环境: 1.前台有且只有一个xss漏洞(不能获取管理员cookie) 2.后台有且只有一个sql注入漏洞(注入漏洞文件只有管理员可以访问) 3.注入获得管理员密码可解密 4.除以上无其他任何漏洞(包括后台getwebshell) 其实

利用DataSet存取SQL Server中的二进制文件

server|二进制 利用DataSet存取SQL Server中的二进制文件 作者 朱二 利用DataSet可以方便的对SQL Server中的二进制文件进行存取与更新操作,下面是详细的代码演示 演示环境: 数据库机器名 :s_test登陆名 :sa密码 :7890数据库名 db_test 下面建立一个表: create table tb_test(id int identity(1,1),photo image ,constraint pk_tb_test primary key(id))