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

缓解行竞争

我们在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

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

  1.     我们可以将所有的键设为一次性的(这也可能产生负面影响,但是目前为止是稳定的)
  2.     大幅压缩键值,这是相当重要的处理

此外,离散的数字键允许我们在将虚拟的离散键值映射到固定数目的键值上,并在此分配单一存储区(我们可以使用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无疑是很适合的。它的文档是那样让人惊讶,那是因为(阅读)其文档的门槛非常的低。虽然他也有折衷(主要是如果你使用持久化),但是他们工作地很好并且比较直观。

那么Redis为您解决什么问题呢?

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

时间: 2024-09-23 07:56:35

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

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

这篇文章主要介绍了利用Redis实现SQL伸缩的方法,包括讲到了锁和时间序列等方面来提升传统数据库的性能,需要的朋友可以参考下. 缓解行竞争 我们在Sentry开发的早起采用的是sentry.buffers. 这是一个简单的系统,它允许我们以简单的Last Write Wins策略来实现非常有效的缓冲计数器. 重要的是,我们借助它完全消除了任何形式的耐久性 (这是Sentry工作的一个非常可接受的方式). 操作非常简单,每当一个更新进来我们就做如下几步: 创建一个绑定到传入实体的哈希键(hash

Windows系统下Java连接SQL Server的方法简介_java

使用JDBC连接SQL Server 设置SQL Server服务器 我使用的是SQL Server 2005标准版SP2,这些都默认即可,一般不用配置.如果需要配置端口请看下面. 1."开始"→"程序"→"Microsoft SQL Server 2005"→"配置工具"→"SQL Server 配置管理器"→"SQL Server 2005 网络配置"→"MSSQLSERV

Redis教程(一):Redis简介_Redis

一.简介: 在过去的几年中,NoSQL数据库一度成为高并发.海量数据存储解决方案的代名词,与之相应的产品也呈现出雨后春笋般的生机.然而在众多产品中能够脱颖而出的却屈指可数,如Redis.MongoDB.BerkeleyDB和CouchDB等.由于每种产品所拥有的特征不同,因此它们的应用场景也存在着一定的差异,下面仅给出简单的说明: 1). BerkeleyDB是一种极为流行的开源嵌入式数据库,在更多情况下可用于存储引擎,比如BerkeleyDB在被Oracle收购之前曾作为MySQL的存储引擎,

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))

php使用pdo连接并查询sql数据库的方法_php技巧

本文实例讲述了php使用pdo连接并查询sql数据库的方法.分享给大家供大家参考. 具体实现代码如下: 复制代码 代码如下: $login = "root"; $passwd = "mysql"; try{   $db=new pdo('mysql:host=localhost;dbname=mysql',$login,$passwd);   foreach($db->query('select * from test') as $row){   print_

zabbix监控redis数据库状态两种方法

方法一,zabbix监控redis 1.导入模板 同样,模板我已上传到 github项目 上 .直接下载,通过下面的步骤导入模板:点击configuration ----> templates ------> import -------> 导入下载的xml文件 . 2.客户端key配置 在被监控的主机上,打开/etc/zabbix/zabbix_agentd.conf 配置文件,在最后一行加入: UserParameter=redis_stats[*],redis-cli -h 127

浅析利用QQ群推广网站的方法

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 QQ这个东西,不用说,会上网的都有一个多个qq号码,不会上网的也有一个qq号码,可见它的流行和使用的人群之广泛.正因为使用人群多,所以我们就有机会利用它来推广你的网站或产品.我们无论使用什么方式推广,都是希望让更多的人了解和知道你的产品或网站.今天分享的是利用qq群来推广,qq群大家也都知道,群根据腾讯官方的分类比如有娱乐类.游戏.教育.商业

[收藏]五种提高 SQL 性能的方法

性能 五种提高 SQL 性能的方法发布日期: 4/1/2004 | 更新日期: 4/1/2004Johnny Papa Data Points Archive 有时, 为了让应用程序运行得更快,所做的全部工作就是在这里或那里做一些很小调整.啊,但关键在于确定如何进行调整!迟早您会遇到这种情况:应用程序中的 SQL 查询不能按照您想要的方式进行响应.它要么不返回数据,要么耗费的时间长得出奇.如果它降低了报告或您的企业应用程序的速度,用户必须等待的时间过长,他们就会很不满意.就像您的父母不想听您解释