9个提升逼格的redis命令(keys,scan,slowlog,rename-command,bigkeys,monitor,info,config,set)

 redis  9个提升逼格的redis命令(keys,scan,slowlog,rename-command,bigkeys,monitor,info,config,set)已关闭评论
9月 082020
 

9个提升逼格的redis命令

非常好的文章,特别是使用bigkeys查找占大内存的key真是方便,推荐https://www.jianshu.com/p/4df5f2356de9

keys

我把这个命令放在第一位,是因为笔者曾经做过的项目,以及一些朋友的项目,都因为使用keys这个命令,导致出现性能毛刺。这个命令的时间复杂度是O(N),而且redis又是单线程执行,在执行keys时即使是时间复杂度只有O(1)例如SET或者GET这种简单命令也会堵塞,从而导致这个时间点性能抖动,甚至可能出现timeout。

强烈建议生产环境屏蔽keys命令(后面会介绍如何屏蔽)。

scan

既然keys命令不允许使用,那么有什么代替方案呢?有!那就是scan命令。如果把keys命令比作类似select * from users where username like '%afei%'这种SQL,那么scan应该是select * from users where id>? limit 10这种命令。

官方文档用法如下:

SCAN cursor [MATCH pattern] [COUNT count]

初始执行scan命令例如scan 0。SCAN命令是一个基于游标的迭代器。这意味着命令每次被调用都需要使用上一次这个调用返回的游标作为该次调用的游标参数,以此来延续之前的迭代过程。当SCAN命令的游标参数被设置为0时,服务器将开始一次新的迭代,而当redis服务器向用户返回值为0的游标时,表示迭代已结束,这是唯一迭代结束的判定方式,而不能通过返回结果集是否为空判断迭代结束。

使用方式:

127.0.0.1:6380> scan 0
1) "22"
2)  1) "23"
    2) "20"
    3) "14"
    4) "2"
    5) "19"
    6) "9"
    7) "3"
    8) "21"
    9) "12"
   10) "25"
   11) "7"

返回结果分为两个部分:第一部分即1)就是下一次迭代游标,第二部分即2)就是本次迭代结果集。

slowlog

上面提到不能使用keys命令,如果就有开发这么做了呢,我们如何得知?与其他任意存储系统例如mysql,mongodb可以查看慢日志一样,redis也可以,即通过命令slowlog。用法如下:

SLOWLOG subcommand [argument]

subcommand主要有:

  • get,用法:slowlog get [argument],获取argument参数指定数量的慢日志。
  • len,用法:slowlog len,总慢日志数量。
  • reset,用法:slowlog reset,清空慢日志。

执行结果如下:

127.0.0.1:6380> slowlog get 5
1) 1) (integer) 2
   2) (integer) 1532656201
   3) (integer) 2033
   4) 1) "flushddbb"
2) 1) (integer) 1  ----  慢日志编码,一般不用care
   2) (integer) 1532646897  ----  导致慢日志的命令执行的时间点,如果api有timeout,可以通过对比这个时间,判断可能是慢日志命令执行导致的
   3) (integer) 26424  ----  导致慢日志执行的redis命令,通过4)可知,执行config rewrite导致慢日志,总耗时26ms+
   4) 1) "config"
      2) "rewrite"

命令耗时超过多少才会保存到slowlog中,可以通过命令config set slowlog-log-slower-than 2000配置并且不需要重启redis。注意:单位是微妙,2000微妙即2毫秒。

rename-command

为了防止把问题带到生产环境,我们可以通过配置文件重命名一些危险命令,例如keys等一些高危命令。操作非常简单,只需要在conf配置文件增加如下所示配置即可:

rename-command flushdb flushddbb
rename-command flushall flushallall
rename-command keys keysys

bigkeys

随着项目越做越大,缓存使用越来越不规范。我们如何检查生产环境上一些有问题的数据。bigkeys就派上用场了,用法如下:

redis-cli -p 6380 --bigkeys

执行结果如下:

... ...
-------- summary -------

Sampled 526 keys in the keyspace!
Total key length in bytes is 1524 (avg len 2.90)

Biggest string found 'test' has 10005 bytes
Biggest   list found 'commentlist' has 13 items

524 strings with 15181 bytes (99.62% of keys, avg size 28.97)
2 lists with 19 items (00.38% of keys, avg size 9.50)
0 sets with 0 members (00.00% of keys, avg size 0.00)
0 hashs with 0 fields (00.00% of keys, avg size 0.00)
0 zsets with 0 members (00.00% of keys, avg size 0.00)

最后5行可知,没有set,hash,zset几种数据结构的数据。string类型有524个,list类型有两个;通过Biggest ... ...可知,最大string结构的key是test,最大list结构的key是commentlist

需要注意的是,这个bigkeys得到的最大,不一定是最大。说明原因前,首先说明bigkeys的原理,非常简单,通过scan命令遍历,各种不同数据结构的key,分别通过不同的命令得到最大的key:

  • 如果是string结构,通过strlen判断;
  • 如果是list结构,通过llen判断;
  • 如果是hash结构,通过hlen判断;
  • 如果是set结构,通过scard判断;
  • 如果是sorted set结构,通过zcard判断。

正因为这样的判断方式,虽然string结构肯定可以正确的筛选出最占用缓存,也可以说最大的key。但是list不一定,例如,现在有两个list类型的key,分别是:numberlist–[0,1,2],stringlist–[“123456789123456789”],由于通过llen判断,所以numberlist要大于stringlist。而事实上stringlist更占用内存。其他三种数据结构hash,set,sorted set都会存在这个问题。使用bigkeys一定要注意这一点。

monitor

假设生产环境没有屏蔽keys等一些高危命令,并且slowlog中还不断有新的keys导致慢日志。那我们如何揪出这些命令是由谁执行的呢?这就是monitor的用处,用法如下:

redis-cli -p 6380 monitor

如果当前redis环境OPS比较高,那么建议结合linux管道命令优化,只输出keys命令的执行情况:

[[email protected] ~]# redis-cli -p 6380 monitor | grep keys 
1532645266.656525 [0 10.0.0.1:43544] "keyss" "*"
1532645287.257657 [0 10.0.0.1:43544] "keyss" "44*"

执行结果中很清楚的看到keys命名执行来源。通过输出的IP和端口信息,就能在目标服务器上找到执行这条命令的进程,揪出元凶,勒令整改。

info

如果说哪个命令能最全面反映当前redis运行情况,那么非info莫属。用法如下:

INFO [section]

section可选值有:

  • Server:运行的redis实例一些信息,包括:redis版本,操作系统信息,端口,GCC版本,配置文件路径等;
  • Clients:redis客户端信息,包括:已连接客户端数量,阻塞客户端数量等;
  • Memory:使用内存,峰值内存,内存碎片率,内存分配方式。这几个参数都非常重要;
  • Persistence:AOF和RDB持久化信息;
  • Stats:一些统计信息,最重要三个参数:OPS(instantaneous_ops_per_sec),keyspace_hitskeyspace_misses两个参数反应缓存命中率;
  • Replication:redis集群信息;
  • CPU:CPU相关信息;
  • Keyspace:redis中各个DB里key的信息;

config

config是一个非常有价值的命令,主要体现在对redis的运维。因为生产环境一般是不允许随意重启的,不能因为需要调优一些参数就修改conf配置文件并重启。redis作者早就想到了这一点,通过config命令能热修改一些配置,不需要重启redis实例,可以通过如下命令查看哪些参数可以热修改:

config get *

热修改就比较容易了,执行如下命令即可:

config set 

例如:config set slowlog-max-len 100config set maxclients 1024

这样修改的话,如果以后由于某些原因redis实例故障需要重启,那通过config热修改的参数就会被配置文件中的参数覆盖,所以我们需要通过一个命令将config热修改的参数刷到redis配置文件中持久化,通过执行如下命令即可:

config rewrite

执行该命令后,我们能在config文件中看到类似这种信息:

# 如果conf中本来就有这个参数,通过执行config set,那么redis直接原地修改配置文件
maxclients 1024
# 如果conf中没有这个参数,通过执行config set,那么redis会追加在Generated by CONFIG REWRITE字样后面
# Generated by CONFIG REWRITE
save 600 60
slowlog-max-len 100

set

set命令也能提升逼格?是的,我本不打算写这个命令,但是我见过太多人没有完全掌握这个命令,官方文档介绍的用法如下:

SET key value [EX seconds] [PX milliseconds] [NX|XX]

你可能用的比较多的就是set key value,或者SETEX key seconds value,所以很多同学用redis实现分布式锁分为两步:首先执行SETNX key value,然后执行EXPIRE key seconds。很明显,这种实现有很严重的问题,因为两步执行不具备原子性,如果执行第一个命令后出现某些未知异常导致无法执行EXPIRE key seconds,那么分布式锁就会一直无法得到释放。

通过SET命令实现分布式锁的正式姿势应该是SET key value EX seconds NX(EX和PX任选,取决于对过期时间精度要求)。另外,value也有要求,最好是一个类似UUID这种具备唯一性的字符串。当然如果问你redis是否还有其他实现分布式锁的方案。你能说出redlock,那对方一定眼前一亮,心里对你竖起大拇指,但嘴上不会说。

redis数据迁移的3个方法

 redis  redis数据迁移的3个方法已关闭评论
1月 172020
 

1. rdb数据备份恢复方法
redis 127.0.0.1:6379> SAVE
OK
或者
redis-cli -h 127.0.0.1 -p 6379 -a pwd bgsave
该命令将在 redis 安装目录中创建dump.rdb文件。

查找dump.rdb文件位置
redis 127.0.0.1:6379> CONFIG GET dir
1) dir
2) /usr/local/redis/bin
以上命令 CONFIG GET dir 输出的 redis 安装目录为 /usr/local/redis/bin
bgsave
创建 redis 备份文件也可以使用命令 BGSAVE,该命令在后台执行。
127.0.0.1:6379> BGSAVE
Background saving started

2. AOF数据备份恢复方法
另一种持久化方式AOF,在配置文件中打开[appendonly yes]。
AOF刷新日志到disk的规则:
appendfsync always #always 表示每次有写操作都进行同步,非常慢,非常安全。
appendfsync everysec #everysec表示对写操作进行累积,每秒同步一次
官方的建议的everysec,安全,就是速度不够快,如果是机器出现问题可能会丢失1秒的数据。

也可以手动执行bgrewriteaof进行AOF备份:
redis-cli -h 127.0.0.1 -p 6379 -a pwd bgrewriteaof

迁移数据恢复
迁移到另外一台恢复数据,需先检查配置文件,将按照以下优先级恢复数据到内存:
如果只配置AOF,重启时加载AOF文件恢复数据;
如果同时 配置了RBDAOF,启动是只加载AOF文件恢复数据;
如果只配置RBD,启动是讲加载dump文件恢复数据;

dump.rdb或者AOF文件迁移到另外一台恢复数据
恢复数据,只需将备份文件 (dump.rdb或者AOF文件) 移动到 redis 安装目录并启动服务即可。

3. redis从库复制数据方法
Redis提供了复制(replication)功能可以自动实现同步的过程。
配置方法
通过配置文件 从数据库的配置文件中加入slaveof master-ip master-port,主数据库无需配置
通过命令行参数 启动redis-server的时候,使用命令行参数–slaveof master-ip master port
redis-server –port 6380 –slaveof 127.0.0.1 6379
通过命令SLAVEOF master-ip master-port
redis>SLAVEOF 127.0.0.1 6379
SLAVEOF NO ONE可以是当前数据库停止接收其他数据库的同步,转成主Redis数据库,程序连接地址都改为新的redisIP地址和端口。

转自:https://my.oschina.net/ppabvc/blog/819448

mac 下 redis 安装、redis.conf位置、redis-server后台运行

 redis  mac 下 redis 安装、redis.conf位置、redis-server后台运行已关闭评论
11月 122019
 

mac下安装redis命令:

brew install redis

 

如果没有安装homebrew,可以打开一个终端,输入下面命令安装:

/usr/bin/ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)”

 

启动:

redis-server 命令直接启动会运行在一个终端里,关闭终端服务就停止了,也没有运行参数可以后台运行,但可以通过修改配置文件参数实现。

mac下brew安装的redis的配置文件默认所在位置: /usr/local/etc/redis.conf

修改: 将 daemonize no 修改为 daemonize yes

 

再启动

redis-server /usr/local/etc/redis.conf

redis就会后台运行了

 

如果要开机启动,使用下面命令:

ln -sfv /usr/local/opt/redis/*.plist ~/Library/LaunchAgents

launchctl load ~/Library/LaunchAgents/homebrew.mxcl.redis.plist

brew services start redis

SpringBoot整合Redis和StringRedisTemplate的使用

 spring, spring-boot  SpringBoot整合Redis和StringRedisTemplate的使用已关闭评论
1月 212019
 

springboot下使用redis非常方便:


Maven依赖

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-data-redis</artifactId>

    <!– <artifactId>spring-boot-starter-redis</artifactId> –>    

</dependency>

 

配置文件 application.properties添加

#redis的ip地址 

spring.redis.hostName=127.0.0.1

#数据库,默认为0

spring.redis.database=1

#端口号 

spring.redis.port=6379

#如果有密码 

spring.redis.password=xxxxx

#客户端超时时间单位是毫秒 默认是2000

spring.redis.timeout=20000 

 

StringRedisTemplate使用

stringRedisTemplate.opsForValue();//操作字符串

stringRedisTemplate.opsForHash();//操作hash

stringRedisTemplate.opsForList();//操作list

stringRedisTemplate.opsForSet();//操作set

stringRedisTemplate.opsForZSet();//操作有序set

示例

import
org.springframework.beans.factory.annotation.Autowired;

import
org.springframework.data.redis.core.StringRedisTemplate;

import org.springframework.stereotype.Service;

 

import java.util.concurrent.TimeUnit;

 

@Service

public class RedisService {

    @Autowired

   
StringRedisTemplate stringRedisTemplate;

 

    /**

     *
stringRedisTemplate基本操作

     */

    public void redis(){

       
stringRedisTemplate.opsForValue().set(“key”, “value”,60*10,
TimeUnit.SECONDS);//向redis里存入数据和设置缓存时间(10分钟)

       
stringRedisTemplate.boundValueOps(“key”).increment(1);//val做1操作

       
stringRedisTemplate.opsForValue().get(“key”);//根据key获取缓存中的val

       
stringRedisTemplate.boundValueOps(“key”).increment(1);//val +1

       
stringRedisTemplate.getExpire(“key”);//根据key获取过期时间

       
stringRedisTemplate.getExpire(“key”,TimeUnit.SECONDS);//根据key获取过期时间并换算成指定单位

       
stringRedisTemplate.delete(“key”);//根据key删除缓存

       
stringRedisTemplate.hasKey(“key”);//检查key是否存在,返回boolean

       
stringRedisTemplate.opsForSet().add(“key”, “5”,”6″,”7″);//向指定key中存放set集合

       
stringRedisTemplate.expire(“key”,1000 ,
TimeUnit.MILLISECONDS);//设置过期时间

       
stringRedisTemplate.opsForSet().isMember(“key”, “1”);//根据key查看集合中是否存在指定数据

       
stringRedisTemplate.opsForSet().members(“key”);//根据key获取set集合

 

    }

}

 

 

celery使用redis队列实例(celery使用入门)

 python  celery使用redis队列实例(celery使用入门)已关闭评论
6月 222016
 


Celery 是一个广泛应用于网络应用程序的任务处理系统。


它可以在以下情况下使用:


在请求响应周期中做网络调用

服务器应当立即响应任何网络请求。如果在请求响应周期内需要进行网络调用,则应在周期外完成调用。例如当用户在网站上注册时,需要发送激活邮件。发送邮件是一种网络调用,耗时2到3秒。用户应该无需等待这2到3秒。因此,发送激活邮件应当在请求响应周期外完成,celery 就能实现这一点。


将一个由几个独立部分组成的大任务分成多个小任务

假设你想知道脸书用户的时间流。脸书提供不同的端点来获取不同的数据。譬如,一个端点用以获取用户时间流中的图片,一个端点获取用户时间流中的博文,一个端点得到用户的点赞信息等。如果你的函数需要和脸书的5个端点依此通信,每个网络调用平均耗时2秒,你将需要10秒完成一次函数执行。但是,你可以把这项工作分为5个独立的任务(你很快就会发现这很容易做到),并让 celery 来处理这些任务。Celery 可以并行地与这5个端点通信,在2秒之内就能得到所有端点的响应。


简单的 celery 例子


假设我们有一个函数,并传给它一个网址列表。该函数需要获取这些网址的响应。


没有使用 celery


创建文件celery_blog.py


import requests  
import time

def func(urls):  
    start = time.time()
    for url in urls:
        resp = requests.get(url)
        print resp.status_code
    print "It took", time.time() - start, "seconds"

if __name__ == "__main__":  
    func(["http://oneapm.com", "http://jd.com", "https://taobao.com", "http://baidu.com", "http://news.oneapm.com"])


运行:


python celery_blog.py 


输出:


使用 celery


调用 celery 的程序中最重要的组成部分为 celery worker。


在 web 应用程序注册的例子中,celery worker 用于发送邮件。


在脸书的例子中, celery worker 用于获取不同的网址。


在我们的 celery_blog.py 例子中, celery worker 用于获取 URL。

celery worker 和你的应用程序/脚本是不同的进程,彼此独立运行。所以你的应用程序/脚本和 celery 需要一些方法来相互沟通。


应用程序代码需要把任务放在 celery worker 可以取出并执行的位置。

譬如,应用程序代码将任务放在消息队列中,celery worker 从消息队列领取任务并执行任务。我们将使用 Redis 作为消息队列。


请确认你已安装 Redis,并可以运行redis-server


请确认你已安装 celery。


修改文件 celery_blog.py,如下:


from celery import Celery

app = Celery('celery_blog',bloker='redis://localhost:6379/1')

@app.task
def fetch_url(url):  
     resp = requests.get(url)
     print resp.status_code

def func(urls):  
     for url in urls:
       fetch_url.delay(url)

if __name__ == "__main__":  
     func(["http://oneapm.com", "http://jd.com", "https://taobao.com", "http://baidu.com", "http://news.oneapm.com"])

代码解释:我们需要一个 celery 实例来启动程序,因此创建了一个名为 app 的 celery 实例。


在3个终端中启动:


第一个终端,运行 redis-server


第二个终端,运行 celery worker -A celery_blog -l info -c 5 ,通过输出可以看到 celery 成功运行。


第三个终端,运行脚本 python celery_blog.py


可以看到第二个终端输出如下:



将 celery 代码和配置保存在不同文件中


上面的例子中,我们只写了一个 celery 任务。但您的项目可能涉及多个模块,您可能希望在不同的模块中有不同的任务。所以让我们将 celery 配置移到单独的文件中。


创建 celery_config.py

from celery import Celery

app = Celery('celery_config', broker='redis://localhost:6379/0', include=['celery_blog']) 

修改 celery_blog.py 代码如下:

import  requests  
from celery_config import app

@app.task
def fetch_url(url):  
     resp = requests.get(url)
     print resp.status_code

def func(urls):  
    for url in urls:
       fetch_url.delay(url)

if __name__ == "__main__":  
    func(["http://oneapm.com", "http://jd.com", "https://taobao.com", "http://baidu.com", "http://news.oneapm.com"])

停掉之前的 celery worker ,运行:


celery worker -A celery_config -l info -c 5 

打开 ipython ,运行如下命令:


In [1]: from celery_blog import func  
In [2]: func(["http://oneapm.com", "http://jd.com", "https://taobao.com", "http://baidu.com", "http://news.oneapm.com"]) 

输出如下:




在不同文件中添加新的任务


您可以添加新的模块,并在该模块中定义一个任务。用以下内容创建一个模块 celery_add.py


from celery_config import app

@app.task
def add(a, b):  
    return a + b


改变 celery_config.py 包含新的模块 celery_add.py,如下:


from celery import Celery

app = Celery('celery_config', broker='redis://localhost:6379/0', include=['celery_blog', 'celery_add']) 


在 ipython 输入:

In [1]: from celery_add import add  
In [2]: add.delay(4, 5) 


输出如下:



在不同的机器上分开使用 Redis 和 celery


到目前为止,我们的脚本、celery worker 和 Redis 都运行在同一机器中。其实并无这种必要,这三者可以运行在不同机器上。


celery 任务涉及到网络请求,因此,在网络优化的机器上使用 celery worker 能提高任务运行速度。Redis 是一种内存数据库,在内存优化的机器上运行效率更高。


在这个例子中,我将在本地系统运行脚本和 celery worker,在分开的服务器上运行 Redis。


修改 celery_config.py 为:


app = Celery('celery_config', broker='redis://192.168.118.148:6379/0', include=['celery_blog']) 

现在我运行任何任务,脚本都将把他放在 Redis 运行的服务器(192.168.118.148)上面。


celery worker 也与 192.168.118.148 沟通,在这个 Redis 服务器上得到任务并执行它。


自己把添加任务的脚本使用下面的方式独立调用:

from celery import Celery

app=Celery(broker=’redis://localhost:6379/1′)

app.send_task("celery_add.add", args=(1000, 2000))

这样似乎就可以真正分开独立了


转自:http://www.wtoutiao.com/p/C980i9.html

英文原文章:http://agiliq.com/blog/2015/07/getting-started-with-celery-and-redis/

9月 302015
 

本文来自Spool的开发者博客,描述了Spool利用Redisbitmaps相关的操作,进行网站活跃用户统计工作。

Redis支持对String类型的value进行基于二进制位的置位操作。通过将一个用户的id对应value上的一位,通过对活跃用户对应的位进行置位,就能够用一个value记录所有活跃用户的信息。如下图所未,下图中的bitmap有9个位被置为1,表示这9个位上对应的用户是今天的活跃用户。其中第15位表示uid为15的用户,第一位表示uid为0的用户。(如果你的uid不是从1开始的,比如从100000开始,实际上你也可以相应的用uid减去初始值来表示其位数,比如1000000用户对应到bitmap的第一位)

具体的代码类似下面这样:

redis.setbit(play:yyyy-mm-dd, user_id, 1)

这样一次记录的复杂度是O(1),在Redis中速度非常快。
而我们通过每天换用一个不同的key来将每天的活跃用户状态记录分开存。并且可以通过一些与或运算计算出N天活跃用户,和连接N天活跃用户这样的统计数据。
如下图,第一行表示星期一的活跃用户情况,第二行表示周二的,以此类推。为样我们通过对N天的活跃用户记录取并集操作,就能得出在N天内活跃过的用户列表。

下面表格表示对应一天,一周,一个月统计时所花费的时间。

Period Time (ms)
Daily 50.2
Weekly 392.0
Monthly 1624.8

下面是具体的java代码片断:

1.算出一天的活跃用户数量

import redis.clients.jedis.Jedis;
import java.util.BitSet;
...
  Jedis redis = new Jedis("localhost");
...
  public int uniqueCount(String action, String date) {
    String key = action + ":" + date;
    BitSet users = BitSet.valueOf(redis.get(key.getBytes()));
    return users.cardinality();
  }

2.计算某几个内活跃用户的数量(某一天活跃就算,所以是取并集)

import redis.clients.jedis.Jedis;
import java.util.BitSet;
...
  Jedis redis = new Jedis("localhost");
...
  public int uniqueCount(String action, String... dates) {
    BitSet all = new BitSet();
    for (String date : dates) {
      String key = action + ":" + date;
      BitSet users = BitSet.valueOf(redis.get(key.getBytes()));
      all.or(users);
    }
    return all.cardinality();
  }

具体的用法还很多,比如你还可以对独特终端的用户单独记一个bitmap,这样就可以统计不同终端用户的活跃情况。有的同学会说用set也能实现同样的效果。但使用set在内存使用量上是会大很多的。

7月 092015
 

摘要:对比传统关系型数据库,NoSQL有着更为复杂的分类——键值、面向文档、列存储以及图数据库。这里就带你一览NoSQL各种类型的适用场景及一些知名公司的方案选择。

在过去几年,关系型数据库一直是数据持久化的唯一选择,数据工作者考虑的也只是在这些传统数据库中做筛选,比如SQL Server、Oracle或者是MySQL。甚至是做一些默认的选择,比如使用.NET的一般会选择SQL Server;使用Java的可能会偏向Oracle,Ruby是MySQL,Python则是PostgreSQL或MySQL等等。

原因很简单:过去很长一段时间内,关系数据库的健壮性已经在多数应用程序中得到证实。我们可以使用这些传统数据库良好的控制并发操作、事务等等。然而如果传统的关系型数据库一直这么可靠,那么还有NoSQL什么事?NoSQL之所以生存并得到发展,是因为它做到了传统关系型数据库做不到的事!

关系型数据库中存在的问题

Impedance Mismatch

 

我们使用Python、Ruby、Java、.Net等语言编写应用程序,这些语言有一个共同的特性——面向对象。但是我们使用MySQL、PostgreSQL、Oracle以及SQL Server,这些数据库同样有一个共同的特性——关系型数据库。这里就牵扯到了“Impedance Mismatch”这个术语:存储结构是面向对象的,但是数据库却是关系的,所以在每次存储或者查询数据时,我们都需要做转换。类似Hibernate、Entity Framework这样的ORM框架确实可以简化这个过程,但是在对查询有高性能需求时,这些ORM框架就捉襟见肘了。

应用程序规模的变大

网络应用程序的规模日渐变大,我们需要储存更多的数据、服务更多的用户以及需求更多的计算能力。为了应对这种情形,我们需要不停的扩展。扩展分为两类:一种是纵向扩展,即购买更好的机器,更多的磁盘、更多的内存等等;另一种是横向扩展,即购买更多的机器组成集群。在巨大的规模下,纵向扩展发挥的作用并不是很大。首先单机器性能提升需要巨额的开销并且有着性能的上限,在Google和Facebook这种规模下,永远不可能使用一台机器支撑所有的负载。鉴于这种情况,我们需要新的数据库,因为关系数据库并不能很好的运行在集群上。不错你也可能会去搭建关系数据库集群,但是他们使用的是共享存储,这并不是我们想要的类型。于是就有了以Google、Facebook、Amazon这些试图处理更多传输所引领的NoSQL纪元。

NoSQL纪元

当下已经存在很多的NoSQL数据库,比如MongoDB、Redis、Riak、HBase、Cassandra等等。每一个都拥有以下几个特性中的一个:

  • 不再使用SQL语言,比如MongoDB、Cassandra就有自己的查询语言
  • 通常是开源项目
  • 为集群运行而生
  • 弱结构化——不会严格的限制数据结构类型

NoSQL数据库的类型

NoSQL可以大体上分为4个种类:Key-value、Document-Oriented、Column-Family Databases以及 Graph-Oriented Databases。下面就一览这些类型的特性:

一、 键值(Key-Value)数据库

键值数据库就像在传统语言中使用的哈希表。你可以通过key来添加、查询或者删除数据,鉴于使用主键访问,所以会获得不错的性能及扩展性。

产品:Riak、Redis、Memcached、Amazon’s Dynamo、Project Voldemort

有谁在使用:GitHub (Riak)、BestBuy (Riak)、Twitter (Redis和Memcached)、StackOverFlow (Redis)、 Instagram (Redis)、Youtube (Memcached)、Wikipedia(Memcached)

适用的场景

储存用户信息,比如会话、配置文件、参数、购物车等等。这些信息一般都和ID(键)挂钩,这种情景下键值数据库是个很好的选择。

不适用场景

1. 取代通过键查询,而是通过值来查询。Key-Value数据库中根本没有通过值查询的途径。

2. 需要储存数据之间的关系。在Key-Value数据库中不能通过两个或以上的键来关联数据。

3. 事务的支持。在Key-Value数据库中故障产生时不可以进行回滚。

二、 面向文档(Document-Oriented)数据库

面向文档数据库会将数据以文档的形式储存。每个文档都是自包含的数据单元,是一系列数据项的集合。每个数据项都有一个名称与对应的值,值既可以是简单的数据类型,如字符串、数字和日期等;也可以是复杂的类型,如有序列表和关联对象。数据存储的最小单位是文档,同一个表中存储的文档属性可以是不同的,数据可以使用XML、JSON或者JSONB等多种形式存储。

产品:MongoDB、CouchDB、RavenDB

有谁在使用:SAP (MongoDB)、Codecademy (MongoDB)、Foursquare (MongoDB)、NBC News (RavenDB)

适用的场景

1. 日志。企业环境下,每个应用程序都有不同的日志信息。Document-Oriented数据库并没有固定的模式,所以我们可以使用它储存不同的信息。

2. 分析。鉴于它的弱模式结构,不改变模式下就可以储存不同的度量方法及添加新的度量。

不适用场景

在不同的文档上添加事务。Document-Oriented数据库并不支持文档间的事务,如果对这方面有需求则不应该选用这个解决方案。

三、 列存储(Wide Column Store/Column-Family)数据库

列存储数据库将数据储存在列族(column family)中,一个列族存储经常被一起查询的相关数据。举个例子,如果我们有一个Person类,我们通常会一起查询他们的姓名和年龄而不是薪资。这种情况下,姓名和年龄就会被放入一个列族中,而薪资则在另一个列族中。

产品:Cassandra、HBase

有谁在使用:Ebay (Cassandra)、Instagram (Cassandra)、NASA (Cassandra)、Twitter (Cassandra and HBase)、Facebook (HBase)、Yahoo!(HBase)

适用的场景

1. 日志。因为我们可以将数据储存在不同的列中,每个应用程序可以将信息写入自己的列族中。

2. 博客平台。我们储存每个信息到不同的列族中。举个例子,标签可以储存在一个,类别可以在一个,而文章则在另一个。

不适用场景

1. 如果我们需要ACID事务。Vassandra就不支持事务。

2. 原型设计。如果我们分析Cassandra的数据结构,我们就会发现结构是基于我们期望的数据查询方式而定。在模型设计之初,我们根本不可能去预测它的查询方式,而一旦查询方式改变,我们就必须重新设计列族。

四、 图(Graph-Oriented)数据库

图数据库允许我们将数据以图的方式储存。实体会被作为顶点,而实体之间的关系则会被作为边。比如我们有三个实体,Steve Jobs、Apple和Next,则会有两个“Founded by”的边将Apple和Next连接到Steve Jobs。

产品:Neo4J、Infinite Graph、OrientDB

有谁在使用:Adobe (Neo4J)、Cisco (Neo4J)、T-Mobile (Neo4J)

适用的场景

1. 在一些关系性强的数据中

2. 推荐引擎。如果我们将数据以图的形式表现,那么将会非常有益于推荐的制定

不适用场景

不适合的数据模型。图数据库的适用范围很小,因为很少有操作涉及到整个图。

转自:http://www.csdn.net/article/2013-07-24/2816330-how-to-choose-nosql-db

Twemproxy——针对MemCached与Redis的代理

 Twemproxy  Twemproxy——针对MemCached与Redis的代理已关闭评论
3月 182013
 
本文来源于我在InfoQ中文站翻译的文章,原文地址是:http://www.infoq.com/cn/news/2012/12/twemproxy

 

 

Twemproxy是一个代理服务器,可以通过它减少MemcachedRedis服务器所打开的连接数。

Twemproxy有何用途呢?它可以:

  • 通过代理的方式减少缓存服务器的连接数
  • 自动在多台缓存服务器间共享数据
  • 通过不同的策略与散列函数支持一致性散列
  • 通过配置的方式禁用失败的结点
  • 运行在多个实例上,客户端可以连接到首个可用的代理服务器
  • 支持请求的流式与批处理,因而能够降低来回的消耗

Redis的创建者Salvatore Sanfilippo(@antirez)撰写了一篇文章,介绍了如何通过Twemproxy在开启Redis-cluster特性前就让Redis集群发挥作用,而在大多数情况下都不会丧失太多的性能:

Twemproxy的强大之处在于可以通过配置的方式让它禁用掉失败的结点,同时还能在一段时间后进行重试,抑或使用指定的键->服务器映射。这意味着在将Redis用作数据存储时,它可以对Redis数据集进行分片(禁用掉结点驱逐);在将Redis用作缓存时,它可以启用结点驱逐以实现简单的高可用性。

Twemproxy速度很快,真的很快,它几乎与直接访问Redis速度一样快。我敢说在最差的情况下,性能也只不过才损失20%而已。


我对性能问题唯一的想法是当在多个实例上使用命令时,我觉得MGET还有改进空间。

Twemproxy早在今年初由Twitter开源,它最开始支持Memcached,最近又添加了对Redis的支持。Twitter使用了大量的缓存服务器,每秒会发送300k的tweet;可以看看这篇介绍Real-Time Delivery Architecture At Twitter以了解更多信息。

查看英文原文:Twemproxy – Proxy For MemCached And Redis

 
 

安装配置及其它资料参考:

 在去年的 QCon London2012 大会上,Twitter 发表了题为 《Timelines @ Twitter》的演讲,里面提到以 Redis 作为其 timeline 的主要存储,目前目测全球范围内,Twitter 可能是 Redis 的最大用户了(或者是新浪微博?)。

  而今天我们要说的这个 Twemproxy,是 Twitter 开源出来的 Redis 和 Memcached 代理。

  功能介绍

  我们知道,无论是 Memcached 还是当前的 Redis,其本身都不具备分布式集群特性,当我们有大量 Redis 或 Memcached 的时候,通常只能通过客户端的一些数据分配算法(比如一致性哈希),来实现集群存储的特性。

  而 Twemproxy 通过引入一个代理层,可以将其后端的多台 Redis 或 Memcached 实例进行统一管理与分配,使应用程序只需要在 Twemproxy 上进行操作,而不用关心后面具体有多少个真实的 Redis 或 Memcached 存储。

  在 Redis 的 Cluster 方案还没有正式推出之前,通过 Proxy 的方式来实现存储集群可能是最好的选择了。更何况 Twemproxy 是通过 Twitter 自身得到了充分检验的产品。

  性能

  根据 Redis 作者的测试结果,在大多数情况下,Twemproxy 的性能相当不错,直接操作 Redis 相比,最多只有 20% 的性能损失。这对于它带来的好处来说真的是微不足道了。唯一可能还有待改进的是其 MGET 操作的效率,其性能只有直接操作 Redis 的 50%。

  安装与配置

  Twemproxy 的安装有点小麻烦,主要命令如下:

apt-get install automake
apt-get install libtool
git clone git://github.com/twitter/twemproxy.git       cd twemproxy
autoreconf -fvi
./configure --enable-debug=log
make
src/nutcracker -h

  通过上面的命令就算安装好了,然后是具体的配置,下面是一个典型的配置

    redis1:
      listen: 0.0.0.0:9999 #使用哪个端口启动 Twemproxy
      redis: true #是否是 Redis 的 proxy
      hash: fnv1a_64 #指定具体的 hash 函数
      distribution: ketama #具体的 hash 算法
      auto_eject_hosts: true #是否在结点无法响应的时候临时摘除结点
      timeout: 400 #超时时间(毫秒)
      server_retry_timeout: 2000 #重试的时间(毫秒)
      server_failure_limit: 1 #结点故障多少次就算摘除掉
      servers: #下面表示所有的 Redis 节点(IP:端口号:权重)
       - 127.0.0.1:6379:1 - 127.0.0.1:6380:1 - 127.0.0.1:6381:1 - 127.0.0.1:6382:1

    redis2:
      listen: 0.0.0.0:10000
      redis: true
      hash: fnv1a_64
      distribution: ketama
      auto_eject_hosts: false
      timeout: 400
      servers:
       - 127.0.0.1:6379:1 - 127.0.0.1:6380:1 - 127.0.0.1:6381:1 - 127.0.0.1:6382:1

  你可以同时开启多个 Twemproxy 实例,它们都可以进行读写,这样你的应用程序就可以完全避免所谓的单点故障。

  问题与不足

  Twemproxy 由于其自身原理限制,有一些不足之处,如:

  • 不支持针对多个值的操作,比如取 sets 的子交并补等(MGET 和 DEL 除外)
  • 不支持 Redis 的事务操作
  • 出错提示还不够完善

  更多

  关于 Twemproxy 的介绍可以看这里:http://antirez.com/news/44

  Twemproxy 项目地址:https://github.com/twitter/twemproxy

 

ubuntu下redis安装配置

 redis, ubuntu  ubuntu下redis安装配置已关闭评论
2月 052013
 

wget http://redis.googlecode.com/files/redis-2.2.4.tar.gz
也可以到redis.io官网下载最新的包

tar -zxf redis-2.2.4.tar.gz
cd redis-2.2.4
make
sudo make install
2. 配置init脚本:

wget https://github.com/ijonas/dotfiles/raw/master/etc/init.d/redis-server
wget https://github.com/ijonas/dotfiles/raw/master/etc/redis.conf
如果错误认证,添加参数 –no-check-certificate

sudo mv redis-server /etc/init.d/redis-server
sudo chmod +x /etc/init.d/redis-server
sudo mv redis.conf /etc/redis.conf

3. 初始化用户和日志路径
第一次启动Redis前,建议为Redis单独建立一个用户,并新建data和日志文件夹
sudo useradd redis
sudo mkdir -p /var/lib/redis
sudo mkdir -p /var/log/redis
sudo chown redis.redis /var/lib/redis
sudo chown redis.redis /var/log/redis

4、设置开机自动启动,关机自动关闭
sudo update-rc.d redis-server defaults

5. 启动Redis:
sudo /etc/init.d/redis-server start

6.启动客户端连接
/usr/local/bin/redis-cli

添加一个服务
#sudo update-rc.d 服务名 defaults 99
删除一个服务
#sudo update-rc.d 服务名 remove
临时重启一个服务
#/etc/init.d/服务名 restart
临时关闭一个服务
#/etc/init.d/服务名 stop
临时启动一个服务
#/etc/init.d/服务名 start

要在虚拟机下使用redis,需要在redis.conf配置文件中加入really-use-vm true

转自: http://who0168.blog.51cto.com/253401/626345