zoukankan      html  css  js  c++  java
  • NoSQL and Redis

    转自:http://www.cnblogs.com/fxjwind/archive/2011/12/10/2283344.html

    首先谈谈为什么需要NoSQL?

    这儿看到一篇blog说的不错http://robbin.iteye.com/blog/524977, 摘录一下

    首先是面对Web2.0网站, 出现的3高问题,

    1、High performance - 对数据库高并发读写的需求 
    web2.0网站要根据用户个性化信息来实时生成动态页面和提供动态信息,所以基本上无法使用动态页面静态化技术,因此数据库并发负载非常高,往往要达到每秒上万次读写请求。关系数据库应付上万次SQL查询还勉强顶得住,但是应付上万次SQL写数据请求,硬盘IO就已经无法承受了。其实对于普通的 BBS网站,往往也存在对高并发写请求的需求,例如像JavaEye网站的实时统计在线用户状态,记录热门帖子的点击次数,投票计数等,因此这是一个相当普遍的需求。 
    2、Huge Storage - 对海量数据的高效率存储和访问的需求 
    类似Facebook,twitter,Friendfeed这样的SNS网站,每天用户产生海量的用户动态,以Friendfeed为例,一个月就达到了2.5亿条用户动态,对于关系数据库来说,在一张2.5亿条记录的表里面进行SQL查询,效率是极其低下乃至不可忍受的。再例如大型web网站的用户登录系统,例如腾讯,盛大,动辄数以亿计的帐号,关系数据库也很难应付。 
    3、High Scalability && High Availability- 对数据库的高可扩展性和高可用性的需求 
    在基于web的架构当中,数据库是最难进行横向扩展的,当一个应用系统的用户量和访问量与日俱增的时候,你的数据库却没有办法像web server和app server那样简单的通过添加更多的硬件和服务节点来扩展性能和负载能力。对于很多需要提供24小时不间断服务的网站来说,对数据库系统进行升级和扩展是非常痛苦的事情,往往需要停机维护和数据迁移,为什么数据库不能通过不断的添加服务器节点来实现扩展呢?

    而对于web2.0网站来说,关系数据库的很多主要特性却往往无用武之地,例如:

    1、数据库事务一致性需求 
    很多web实时系统并不要求严格的数据库事务,对读一致性的要求很低,有些场合对写一致性要求也不高。因此数据库事务管理成了数据库高负载下一个沉重的负担。 
    2、数据库的写实时性和读实时性需求 
    对关系数据库来说,插入一条数据之后立刻查询,是肯定可以读出来这条数据的,但是对于很多web应用来说,并不要求这么高的实时性,比方说我(JavaEye的robbin)发一条消息之后,过几秒乃至十几秒之后,我的订阅者才看到这条动态是完全可以接受的。 
    3、对复杂的SQL查询,特别是多表关联查询的需求 
    任何大数据量的web系统,都非常忌讳多个大表的关联查询,以及复杂的数据分析类型的复杂SQL报表查询,特别是SNS类型的网站,从需求以及产品设计角度,就避免了这种情况的产生。往往更多的只是单表的主键查询,以及单表的简单条件分页查询,SQL的功能被极大的弱化了。

    Redis Cookbook

    1 Introduction

    1.1 Are your application and data a good fit for NoSQL?

    When working on the web, chances are your data and data model keep changing with added functionality and business updates. Evolving the schema to support these changes in a relational database is a painful process, especially if you can’t really afford downtime—which people most often can’t these days, because applications are expected to run 24/7.

    Examples of data that are a particularly good fit for nonrelation storage are transactional details, historical data, and server logs. These are normally highly dynamicchanging quite often, and their storage tends to grow quite quickly, also don’t typically feel “relational”.

    ACID,指数据库事务正确执行的四个基本要素的缩写

    原子性(Atomicity)

    整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。

    一致性(Consistency)

    在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。

    隔离性(Isolation)

    两个事务的执行是互不干扰的,一个事务不可能看到其他事务运行时,中间某一时刻的数据。

    持久性(Durability)

    在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。

    Performance can also be a key factor. NoSQL databases are generally faster, particularly for write operations, making them a good fit for applications that are write-heavy.

    NoSQL databases generally don’t provide ACID or do it only partially.

    Redis provides partial ACID compliance by design due to the fact that it is single threaded (which guarantees consistency and isolation), and full compliance if configured with appendfsync always, providing durability as well.

    Once you’ve weighted all the options, picking between SQL (for stable, predictable, relational data) and NoSQL (for temporary, highly dynamic data) should be an easy task.

    There are also big differences between NoSQL databases that you should account for.

    MongoDB (a popular NoSQL database) is a feature-heavy document database that allows you to perform range queries, regular expression searches, indexing, and MapReduce.

    Redis is extremely fast, making it perfectly suited for applications that are write-heavy, data that changes often, and data that naturally fits one of Redis’s data structures (for instance, analytics data).

    1.2 Using Redis Data Types

    Unlike most other NoSQL solutions and key-value storage engines, Redis includes several built-in data types, allowing developers to structure their data in meaningful semantic ways—with the added benefit of being able to perform data-type specific operations inside Redis, which is typically faster than processing the data externally.

    Strings 
    The simplest data type in Redis is a string. Strings are also the typical (and frequently the sole) data type in other key-value storage engines. You can store strings of any kind, including binary data. You might, for example, want to cache image data for avatars in a social network. The only thing you need to keep in mind is that a specific value inside Redis shouldn’t go beyond 512MB of data.

    Lists 
    Lists in Redis are ordered lists of binary safe strings, implemented on the idea of a linked list.

    是用linked list实现的, 而不是用数组, 所以不适合按index去取, 比较适合实现queue和stack

    Hashes 
    Much like traditional hashtables, hashes in Redis store several fields and their values inside a specific key.

    象python里面的字典, 非常有用的结构

    Sets and Sorted Sets 
    Sets in Redis are an unordered collection of binary-safe strings. Elements in a given set can have no duplicates. Sets allow you to perform typical set operations such as intersections and unions.

    对于web应用, 如朋友圈...

    1.3 Using Redis from Python with redis-py

    easy_install redis

    >>> import redis 
    >>> redis = redis.Redis(host='localhost', port=6379, db=0) 
    >>> redis.smembers('circle:jdoe:soccer') 
    set(['users:toby', 'users:adam', 'users:apollo', 'users:mike']) 
    >>> redis.sadd('circle:jdoe:soccer', 'users:fred') 
    True

    In order to squeeze a bit more performance out of your Redis and Python setup, you may want to install the Python bindings for Hiredis, a C-based Redis client library developed by the Redis authors.

    easy_install hiredis

    redis-py will then automatically detect the Python bindings and use Hiredis to connect to the server and process responses—hopefully much faster than before.

    2 Leveraging Redis

    2.1 Using Redis as a Key/Value Store

    Storing application usage counters

    Let’s begin by storing something quite basic: counters. Imagine we run a business social network and want to track profile/page visit data. We could just add a column to whatever table is storing our page data in our RDBMS, but hopefully our traffic is high enough that updates to this column have trouble keeping up. We need something much faster to update and to query. So we’ll use Redis for this instead.

    SET visits:1:totals 21389 
    SET visits:2:totals 1367894 
    INCR visits:635:totals 
    GET visits:635:totals

    Storing object data in hashes

    实现了类似python字典的功能

    Let’s also assume we want to store a number of fields about our users, such as a full name, email address, phone number, and number of visits to our application. We’ll use Redis’s hash management commands—like HSET, HGET, and HINCRBY—to store this 
    information.

    redis> hset users:jdoe name "John Doe" 
    (integer) 1 
    redis> hset users:jdoe email "jdoe@test.com" 
    (integer) 1 
    redis> hset users:jdoe phone "+1555313940" 
    (integer) 1 
    redis> hincrby users:jdoe visits 1 
    (integer) 1

    redis> hget users:jdoe email 
    "jdoe@test.com" 
    redis> hgetall users:jdoe 
    1) "name" 
    2) "John Doe" 
    3) "email" 
    4) "jdoe@test.com" 
    5) "phone" 
    6) "+1555313940" 
    7) "visits" 
    8) "1"

    Storing user “Circles” using sets

    Let’s look at how we can use Redis’s support for sets to create functionality similar to the circles in the recently launched Google+. Sets are a natural fit for circles, because sets represent collections of data, and have native functionality to do interesting things like intersections and unions.

    redis> sadd circle:jdoe:family users:anna 
    (integer) 1 
    redis> sadd circle:jdoe:family users:richard

    (integer) 1 
    redis> sadd circle:jdoe:family users:mike 
    (integer) 1

    redis> sadd circle:jdoe:family users:mike 
    (integer) 1 
    redis> sadd circle:jdoe:soccer users:mike 
    (integer) 1 
    redis> sadd circle:jdoe:soccer users:adam 
    (integer) 1 
    redis> sadd circle:jdoe:soccer users:toby 
    (integer) 1 
    redis> sadd circle:jdoe:soccer users:apollo 
    (integer) 1

    redis> sinter circle:jdoe:family circle:jdoe:soccer 
    1) "users:mike" 
    redis> sunion circle:jdoe:family circle:jdoe:soccer 
    1) "users:anna" 
    2) "users:mike" 
    3) "users:apollo" 
    4) "users:adam" 
    5) "users:richard" 
    6) "users:toby"

    2.2 Inspecting Your Data

    While developing (or perhaps debugging) with Redis, you may find you need to take a look at your data. Even though it’s not as simple (or powerful) as MySQL’s SHOW TABLES; and SELECT * FROM table WHERE conditions; commands, there are ways of viewing data with Redis.

    KEYS pattern 
    Lists all the keys in the current database that match the given pattern. 
    TYPE key-name 
    Tells the type of the key. Possible types are: string, list, hash, set, zset, and none. 
    MONITOR 
    Outputs the commands received by the Redis server in real time.

    Keep in mind that every time you use the KEYS command, Redis has to scan all the keys in the database. Therefore, this can really slow down your server, so you probably shouldn’t use it as a normal operation. If you need a list of all your keys (or a subset) you might want to add those keys to a set and then query it. 慎用Keys, 因为需要遍历所有keys, overload server

    2.3 Implementing OAuth on Top of Redis

    http://zh.wikipedia.org/zh/OAuth

    对于OAuth不是很熟悉, 其实是通过这个场景介绍了数据过期设置, 可以设置key的有效时间, 过期自动删除.

    对于认证和授权是有时限的, 用Redis提供的这个特性很合适.

    EXPIRE key seconds 
    Sets an expiration timeout on a key, after which it will be deleted. This can be used on any type of key (strings, hashes, lists, sets or sorted sets) and is one of the most powerful Redis features. 
    EXPIREAT key timestamp 
    Performs the same operation as EXPIRE, except you can specify a UNIX timestamp (seconds since midnight, January 1, 1970) instead of the number of elapsed seconds. 
    TTL key 
    Tells you the remaining time to live of a key with an expiration timeout. 
    PERSIST key 
    Removes the expiration timeout on the given key.

    2.4 Using Redis’s Pub/Sub Functionality to Create a Chat System

    通过聊天室场景来介绍Redis另一个非常有用的功能, 发布/订阅(publish/subscribe)功能类似于传统的消息路由功能,发布者发布消息,订阅者接收消息,沟通发布者和订阅者之间的桥梁是订阅的channel或者pattern. 这种设计模式实现了两者之间的松耦合.

    Redis就是一种基于内存的服务器, 客户端可以通过简单的命令, 进行创建Chanel, subscribe, publish的操作, 有Redis来保存chanel状态并负责消息路由和发送. 这个功能和他提供的基本功能不一样, 算是副业.

    PUBLISH 
    Publishes to a specific channel 
    SUBSCRIBE 
    Subscribes to a specific channel 
    UNSUBSCRIBE 
    Unsubscribes from a specific channel

    PSUBSCRIBE, 批量订阅 
    Subscribes to channels that match a given pattern 
    PUNSUBSCRIBE 
    Unsubscribes from channels that match a given pattern

    2.5 Implementing an Inverted-Index Text Search with Redis

    用Redis实现一个内存倒排索引相当容易的, 因为它本身对数据结构的支持.

    在生成索引时, 为每个word创建doc_id的集合

    $redis.sadd("word:#{word}", doc_id)

    在search的时候, 把所有搜索word的doc_id集合求交集

    $redis.sinter(*terms.map{|t| "word:#{t}"})

    相当简单.但是这章通过这个场景是为了介绍Redis的事务特性

    document_ids = redis.multidoredis.zinterstore("temp_set", terms.map{|t| "word:#{t}"}) 
        $redis.zrevrange("temp_set", 0, -1) 
    end.last

    The MULTI and EXEC commands allow transactional behavior in Redis.

    Using DISCARD inside a transaction will abort the transaction, discarding all the commands and return to the normal state.

    上面那段代码是在search中用到, zinterstore会创建一个temp_set存放临时结果, 如果多个客户端调用search的时候, 这个temp_set就会冲突, race condition.

    做法就是把这段代码加到Multi…last的事务中, EXEC会由Redis在Last时, 自动调用.

    Redis也是基于异步系统的, 异步系统是单线程的, 所以通过这个方法可以解决这个问题.

    2,6 Analytics and Time-Based Data

    Storing analytics or other time-based data poses somewhat of a challenge for traditional storage systems (like an RDBMS). Perhaps you want to do rate limiting on incoming traffic (which requires fast and highly concurrent updates) or simply track visitors (or more complex metrics) to your website and plot them on a chart.

    这是Redis一个非常典型和完美的应用, 实时数据统计, 对于关系数据库, 这种短时间内, 大量快速的更新, 和海量的查询, 明显是力不从心的.

    Redis is ideally suited for storing this type of data, and for tracking events in particular. 
    A good and memory-efficient way of storing this data in Redis is to use hashes to store the counters, increment them using HINCRBY, and then fetch them using HGET and HMGET. Finding the top elements is also easily achieved using the SORT command.

    2.7 Implementing a Job Queue with Redis

    A typical use case for Redis has been a queue. Although this is owed mostly to Resque (a project started by Github after trying all the other Ruby job queueing solutions). In fact, there are several other implementations (Barbershop, qr, presque) and tutorials 
    (“Creating Processing Queues with Redis”). Nevertheless, it’s interesting in the context of this book to give an example implementation (inspired by existing ones).

    这也是Redis一个典型的应用, Redis可以被看作是共享内存, 作为进程间的消息queue, 再合适不过...

    3 Redis Administration and Maintenance

    3.1 Configuring Persistence 
    One of the advantages of Redis over other key/value stores like memcached is its support for persistence.

    (1)The default persistence model is snapshotting, which consists of saving the entire database to disk in the RDB format (basically a compressed database dump). This can be done periodically at set times, or every time a configurable number of keys changes.

    You can manually trigger snapshotting with the SAVE and BGSAVE commands. SAVE performs the same operation as BGSAVE but does so in the foreground, thereby blocking your Redis server.

    If you come to the conclusion that snapshotting is putting too much strain on your Redis servers you might want to consider using slaves for persistence (by commenting out all the save statements in your masters and enabling them only on the slaves), or using AOF instead.

    (2)The alternative is using an Append Only File (AOF). This might be a better option if you have a large dataset or your data doesn’t change very frequently.

    The Append Only File persistence mode keeps a log of the commands that change your dataset in a separate file. Like most writes on modern operating systems, any data logged to AOF is left in memory buffers and written to disk at intervals of a few secondsusing the system’s fsync call. You can configure how often the AOF gets synched to disk by putting appendfsync statements in your configuration file. Valid options are always, everysec, and no.

    3.2 Starting a Redis Slave

    Database slaves are useful for a number of reasons. You might need them to loadbalance your queries, keep hot standby servers, perform maintenance operations, or simply inspect your data.

    Redis supports master-slave replication natively: you can have multiple slaves per master and slaves connecting to slaves. You can configure replication on the configuration file before starting a server or by connecting to a running server and using the SLAVEOFcommand.

    3.3 Handling a Dataset Larger Than Memory

    Often you might find yourself with a dataset that won’t fit in your available memory. 
    While you could try to get around that by adding more RAM or sharding (which in addition would allow you you to scale horizontally), it might not be feasible or practical to do so.

    Redis has supported a feature called Virtual Memory (VM) since version 2.0. This allows you to have a dataset bigger than your available RAM by swapping rarely used values to disk and keeping all the keys and the frequently used values in memory. 
    However, this has one downside: before Redis reads or performs an operation on swapped values, they must be read into real memory.

    任何东西都是balance, VM就是时间换空间, 所以使用VM必然带来tradeoff,

    If you decide to use VM, you should be aware of its ideal use cases and the tradeoffs you’re making. 
    • The keys are always kept in memory. This means that if you have a big number of small keys, VM might not be the best option for you or you might have the change your data structure and use large strings, hashes, lists, or sets instead. 对于Redis, 因为它提供丰富的数据结果, 所以尽量使用数据结构来封装数据, 而不应该单纯将数据以kv的格式存放, 明显大量的key会降低Redis系统的效率. 
    • VM is ideal for some patterns of data access, not all. If you regularly query all your data, VM is probably not a good fit because your Redis server might end up blocking clients in order to fetch the values from disk. VM is ideally suited for situations when you have a reasonable amount of frequently accessed values that fit in memory. 
    • Doing a full dump of your Redis server will be extremely slow. In order to generate a snapshot, Redis needs to read all the values swapped to disk in order to write them to the RDB file (see “Configuring Persistence” on page 45). This generates a lot of I/O. Due to this, it might be better for you to use AOF as a persistence mode. 
    • VM also affects the speed of replication, because Redis masters need to perform a BGSAVE when a new slave connects.

    3.4 Upgrading Redis

    Our solution will involve starting a new Redis server in slave mode, switching over the clients to the slave and promoting the new server to the master role.

    3.5 Backing up Redis

    Our proposed solution is heavily dependent on your Redis persistence model: 
    • With the default persistence model (snapshotting), you’re best off using a snapshot as a backup. 
    • If you’re using only AOF, you’ll have to back up your log in order to be able to replay it on startup. 
    • If you’re running your Redis in VM mode, you might want to use an AOF log for the purpose of backups, as the use of snapshotting is not advised with VM.

    3.6 Sharding Redis

    Sharding is a horizontal partitioning tecnique often used with databases. It allows you to scale them by distributing your data across several database instances. Not only does this allow you to have a bigger dataset, as you can use more memory, it will also help if CPU usage is the problem, since you can distribute your instances through different servers (or servers with multiple CPUs). 
    In Redis’s case, sharding can be easily implemented in the client library or application.

    Redis的一些资源

     

    Redis, from the Ground Up

    http://blog.mjrusso.com/2010/10/17/redis-from-the-ground-up.html

    Redis tutorial

    http://simonwillison.net/static/2010/redis-tutorial/

    Redis几个认识误区

    转一篇博客, 因为要翻*墙才能访问, 觉得写的不错.

    http://timyang.net/data/redis-misunderstanding/

    Saturday, Dec 4th, 2010 by Tim | Tags: key value storeredis

    前几天微博发生了一起大的系统故障,很多技术的朋友都比较关心,其中的原因不会超出James Hamilton在On Designing and Deploying Internet-Scale Service(1)概括的那几个范围,James第一条经验“Design for failure”是所有互联网架构成功的一个关键。互联网系统的工程理论其实非常简单,James paper中内容几乎称不上理论,而是多条实践经验分享,每个公司对这些经验的理解及执行力决定了架构成败。

    题外话说完,最近又研究了Redis。去年曾做过一个MemcacheDB, Tokyo Tyrant, Redis performance test,到目前为止,这个benchmark结果依然有效。这1年我们经历了很多眼花缭乱的key value存储产品的诱惑,从Cassandra的淡出(Twitter暂停在主业务使用)到HBase的兴起(Facebook新的邮箱业务选用 HBase(2)),当再回头再去看Redis,发现这个只有1万多行源代码的程序充满了神奇及大量未经挖掘的特性。Redis性能惊人,国内前十大网站的子产品估计用1台Redis就可以满足存储及Cache的需求。除了性能印象之外,业界其实普遍对Redis的认识存在一定误区。本文提出一些观点供大家探讨。

    1. Redis是什么

    这个问题的结果影响了我们怎么用Redis。如果你认为Redis是一个key value store, 那可能会用它来代替MySQL;如果认为它是一个可以持久化的cache, 可能只是它保存一些频繁访问的临时数据。Redis是REmote DIctionary Server的缩写,在Redis在官方网站的的副标题是A persistent key-value database with built-in net interface written in ANSI-C for Posix systems,这个定义偏向key value store。还有一些看法则认为Redis是一个memory database,因为它的高性能都是基于内存操作的基础。另外一些人则认为Redis是一个data structure server,因为Redis支持复杂的数据特性,比如List, Set等。对Redis的作用的不同解读决定了你对Redis的使用方式。

    互联网数据目前基本使用两种方式来存储,关系数据库或者key value。但是这些互联网业务本身并不属于这两种数据类型,比如用户在社会化平台中的关系,它是一个list,如果要用关系数据库存储就需要转换成一种多行记录的形式,这种形式存在很多冗余数据,每一行需要存储一些重复信息。如果用key value存储则修改和删除比较麻烦,需要将全部数据读出再写入。Redis在内存中设计了各种数据类型,让业务能够高速原子的访问这些数据结构,并且不需要关心持久存储的问题,从架构上解决了前面两种存储需要走一些弯路的问题。

    2. Redis不可能比Memcache快

    很多开发者都认为Redis不可能比Memcached快,Memcached完全基于内存,而Redis具有持久化保存特性,即使是异步的,Redis也不可能比Memcached快。但是测试结果基本是Redis占绝对优势。一直在思考这个原因,目前想到的原因有这几方面。

    • Libevent。和 Memcached不同,Redis并没有选择libevent。Libevent为了迎合通用性造成代码庞大(目前Redis代码还不到 libevent的1/3)及牺牲了在特定平台的不少性能。Redis用libevent中两个文件修改实现了自己的epoll event loop(4)。业界不少开发者也建议Redis使用另外一个libevent高性能替代libev,但是作者还是坚持Redis应该小巧并去依赖的思路。一个印象深刻的细节是编译Redis之前并不需要执行./configure。
    • CAS问题。CAS是Memcached中比较方便的一种防止竞争修改资源的方法。CAS实现需要为每个cache key设置一个隐藏的cas token,cas相当value版本号,每次set会token需要递增,因此带来CPU和内存的双重开销,虽然这些开销很小,但是到单机10G+ cache以及QPS上万之后这些开销就会给双方相对带来一些细微性能差别(5)。
    3. 单台Redis的存放数据必须比物理内存小

    Redis的数据全部放在内存带来了高速的性能,但是也带来一些不合理之处。比如一个中型网站有100万注册用户,如果这些资料要用Redis来存储,内存的容量必须能够容纳这100万用户。但是业务实际情况是100万用户只有5万活跃用户,1周来访问过1次的也只有15万用户,因此全部100万用户的数据都放在内存有不合理之处,RAM需要为冷数据买单。

    这跟操作系统非常相似,操作系统所有应用访问的数据都在内存,但是如果物理内存容纳不下新的数据,操作系统会智能将部分长期没有访问的数据交换到磁盘,为新的应用留出空间。现代操作系统给应用提供的并不是物理内存,而是虚拟内存(Virtual Memory)的概念。

    基于相同的考虑,Redis 2.0也增加了VM特性。让Redis数据容量突破了物理内存的限制。并实现了数据冷热分离。

    4. Redis的VM实现是重复造轮子

    Redis的VM依照之前的epoll实现思路依旧是自己实现。但是在前面操作系统的介绍提到OS也可以自动帮程序实现冷热数据分离,Redis只需要OS申请一块大内存,OS会自动将热数据放入物理内存,冷数据交换到硬盘,另外一个知名的“理解了现代操作系统(3)”的Varnish就是这样实现,也取得了非常成功的效果。

    作者antirez在解释为什么要自己实现VM中提到几个原因(6)。主要OS的VM换入换出是基于Page概念,比如OS VM1个Page是4K, 4K中只要还有一个元素即使只有1个字节被访问,这个页也不会被SWAP, 换入也同样道理,读到一个字节可能会换入4K无用的内存。而Redis自己实现则可以达到控制换入的粒度。另外访问操作系统SWAP内存区域时block 进程,也是导致Redis要自己实现VM原因之一。

    5. 用get/set方式使用Redis

    作为一个key value存在,很多开发者自然的使用set/get方式来使用Redis,实际上这并不是最优化的使用方法。尤其在未启用VM情况下,Redis全部数据需要放入内存,节约内存尤其重要。

    假如一个key-value单元需要最小占用512字节,即使只存一个字节也占了512字节。这时候就有一个设计模式,可以把key复用,几个key-value放入一个key中,value再作为一个set存入,这样同样512字节就会存放10-100倍的容量。

    这就是为了节约内存,建议使用hashset而不是set/get的方式来使用Redis,详细方法见参考文献(7)。

    6. 使用aof代替snapshot

    Redis有两种存储方式,默认是snapshot方式,实现方法是定时将内存的快照(snapshot)持久化到硬盘,这种方法缺点是持久化之后如果出现crash则会丢失一段数据。因此在完美主义者的推动下作者增加了aof方式。aof即append only mode,在写入内存数据的同时将操作命令保存到日志文件,在一个并发更改上万的系统中,命令日志是一个非常庞大的数据,管理维护成本非常高,恢复重建时间会非常长,这样导致失去aof高可用性本意。另外更重要的是Redis是一个内存数据结构模型,所有的优势都是建立在对内存复杂数据结构高效的原子操作上,这样就看出aof是一个非常不协调的部分。

    其实aof目的主要是数据可靠性及高可用性,在Redis中有另外一种方法来达到目的:Replication。由于Redis的高性能,复制基本没有延迟。这样达到了防止单点故障及实现了高可用。

    小结

    要想成功使用一种产品,我们需要深入了解它的特性。Redis性能突出,如果能够熟练的驾驭,对国内很多大型应用具有很大帮助。希望更多同行加入到Redis使用及代码研究行列。

    ————————————————————————————————————————————————————————————————————————

    另附:

    1.Redis 是什么?
    2 Redis用来做什么?
    3 Redis的优点?
    4 Redis的缺点?





    阅读目的: 对什么是内存型数据库有概念性的认知。?



    Redis 是什么?

        通常而言目前的数据库分类有几种,包括 SQL/NSQL,,关系数据库,键值数据库等等 等,分类的标准也不以,Redis本质上也是一种键值数据库的,但它在保持键值数据库简单快捷特点的同时,又吸收了部分关系数据库的优点。从而使它的位置处于关系数据库和键值数 据库之间。Redis不仅能保存Strings类型的数据,还能保存Lists类型(有序)和Sets类型(无序)的数据,而且还能完成排序(SORT) 等高级功能,在实现INCR,SETNX等功能的时候,保证了其操作的原子性,除此以外,还支持主从复制等功能。

      更为详细的描述请参考如下:

            http://code.google.com/p/redis/wiki/index

      Redis官方也同样提供了一个名为Retwis的项目代码,可以对照着官方学习。

    2 Redis用来做什么?

            通常局限点来说,Redis也以消息队列的形式存在,作为内嵌的List存在,满足实时的高并发需求。而通常在一个电商类型的数据处理过程之中,有关商品,热销,推荐排序的队列,通常存放在Redis之中,期间也包扩Storm对于Redis列表的读取和更新。


    3 Redis的优点

    性能极高 – Redis能支持超过 100K+ 每秒的读写频率。

    丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。

    原子 – Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。

    丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。

    4 Redis的缺点

    是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。

        总结: Redis受限于特定的场景,专注于特定的领域之下,速度相当之快,目前还未找到能替代使用产品。

    ——————————————————————————————————————————————————————————————————————————

    Redis是什么?两句话可以做下概括: 
    1. 是一个完全开源免费的key-value内存数据库 
    2. 通常被认为是一个数据结构服务器,主要是因为其有着丰富的数据结构 strings、map、 list、sets、 sorted sets
    Redis不是什么?同样从两个方面来做下对比: 
    1. 不是sql server、mySQL等关系型数据库,主要原因是: 
         . redis目前还只能作为小数据量存储(全部数据能够加载在内存中) ,海量数据存储方面并不是redis所擅长的领域 
         . 设计、实现方法很不一样.关系型数据库通过表来存储数据,通过SQL来查询数据。而Redis通上述五种数据结构来存储数据,通过命令 来查询数据 
    2.   不是Memcached等缓存系统,主要原因有以下几个: 
         .网络IO模型方面:Memcached是多线程,分为监听线程、worker线程,引入锁,带来了性能损耗。Redis使用单线程的IO复用模型,将速度优势发挥到最大,也提供了较简单的计算功能 
         .内存管理方面:Memcached使用预分配的内存池的方式,带来一定程度的空间浪费 并且在内存仍然有很大空间时,新的数据也可能会被剔除,而Redis使用现场申请内存的方式来存储数据,不会剔除任何非临时数据 Redis更适合作为存储而不是cache 
         .数据的一致性方面:Memcached提供了cas命令来保证.而Redis提供了事务的功能,可以保证一串 命令的原子性,中间不会被任何操作打断 
         . 存储方式方面:Memcached只支持简单的key-value存储,不支持枚举,不支持持久化和复制等功能
       一句话小结一下:Redis是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部分场合可以对关系数据库起到很好的补充作用。
    Redis有什么用?只有了解了它有哪些特性,我们在用的时候才能扬长避短,为我们所用: 
    1. 速度快:使用标准C写,所有数据都在内存中完成,读写速度分别达到10万/20万 
    2. 持久化:对数据的更新采用Copy-on-write技术,可以异步地保存到磁盘上,主要有两种策略,一是根据时间,更新次数的快照(save 300 10 )二是基于语句追加方式(Append-only file,aof) 
    3. 自动操作:对不同数据类型的操作都是自动的,很安全 
    4. 快速的主--从复制,官方提供了一个数据,Slave在21秒即完成了对Amazon网站10G key set的复制。 
    5. Sharding技术: 很容易将数据分布到多个Redis实例中,数据库的扩展是个永恒的话题,在关系型数据库中,主要是以添加硬件、以分区为主要技术形式的纵向扩展解决了很多的应用场景,但随着web2.0、移动互联网、云计算等应用的兴起,这种扩展模式已经不太适合了,所以近年来,像采用主从配置、数据库复制形式的,Sharding这种技术把负载分布到多个特理节点上去的横向扩展方式用处越来越多。
    这里对Redis数据库做下小结: 
    1. 提高了DB的可扩展性,只需要将新加的数据放到新加的服务器上就可以了 
    2. 提高了DB的可用性,只影响到需要访问的shard服务器上的数据的用户 
    3. 提高了DB的可维护性,对系统的升级和配置可以按shard一个个来搞,对服务产生的影响较小 
    4. 小的数据库存的查询压力小,查询更快,性能更好
       写到这里,可能就会有人急不可待地想用它了,那怎么用呢?可以直接到官方文档,里面帮我们整理好了各个语言环境下的客户端,主要有Ruby、Python、 PHP、Perl、Lua、Java、C#....有几种语言,我也没见过,所以就不多说了,你懂的....
    最后,把我使用过程中的一些 经验与教训,做个小结: 
    1. 要进行Master-slave配置,出现服务故障时可以支持切换。 
    2. 在master侧禁用数据持久化,只需在slave上配置数据持久化。 
    3. 物理内存+虚拟内存不足,这个时候dump一直死着,时间久了机器挂掉。这个情况就是灾难! 
    4. 当Redis物理内存使用超过内存总容量的3/5时就会开始比较危险了,就开始做swap,内存碎片大 
    5. 当达到最大内存时,会清空带有过期时间的key,即使key未到过期时间. 
    6. redis与DB同步写的问题,先写DB,后写redis,因为写内存基本上没有问题
  • 相关阅读:
    C#下解决DrawImage画出来的Image变大了的问题
    WPF的TextBox产生内存泄露的情况
    【技术积累】【C#】创建符号链接
    Wix学习整理(7)——在开始菜单中为HelloWorld添加卸载快捷方式
    Wix学习整理(5)——安装时填写注册表
    Wix学习整理(4)——关于WiX文件格式和案例HelloWorld的分析
    【技术积累】【C#】生成字符串的MD5值
    Wix学习整理(6)——安装快捷方式
    【小技巧积累】设置ListView控件的Item不在Tab键导航序列中
    修改Windows的本地hosts文件以访问facebook
  • 原文地址:https://www.cnblogs.com/cxzdy/p/5128970.html
Copyright © 2011-2022 走看看