Redis Replication

Continuing on my series of introductory posts on Redis DB, today i’ll address the subject of replication.

 

Definition:

  • Replication is a method by which other servers receive a continuously updated copy of the data as it’s being written, so that the replicas can service read queries.

 

Basic info (redis.io):

  • Redis uses asynchronous replication. Starting with Redis 2.8 there is however a periodic (one time every second) acknowledge of the replication stream processed by slaves.
  • A master can have multiple slaves.
  • Slaves are able to accept other slaves connections. Aside from connecting a number of slaves to the same master, slaves can also be connected to other slaves in a graph-like structure.
  • Redis replication is non-blocking on the master side, this means that the master will continue to serve queries when one or more slaves perform the first synchronization.
  • Replication is non blocking on the slave side: while the slave is performing the first synchronization it can reply to queries using the old version of the data set, assuming you configured Redis to do so in redis.conf. Otherwise you can configure Redis slaves to send clients an error if the link with the master is down. However there is a moment where the old dataset must be deleted and the new one must be loaded by the slave where it will block incoming connections.
  • Replications can be used both for scalability, in order to have multiple slaves for read-only queries (for example, heavy SORT operations can be offloaded to slaves), or simply for data redundancy.
  • It is possible to use replication to avoid the saving process on the master side: just configure your master redis.conf to avoid saving (just comment all the “save” directives), then connect a slave configured to save from time to time.

 

How Redis replication works (redis.io):

  • If you set up a slave, upon connection it sends a SYNC command. And it doesn’t matter if it’s the first time it has connected or if it’s a re-connection.
  • The master then starts background saving, and collects all new commands received that will modify the dataset. When the background saving is complete, the master transfers the database file to the slave, which saves it on disk, and then loads it into memory. The master will then send to the slave all accumulated commands, and all new commands received from clients that will modify the dataset. This is done as a stream of commands and is in the same format of the Redis protocol itself.
  • You can try it yourself via telnet. Connect to the Redis port while the server is doing some work and issue the SYNC command. You’ll see a bulk transfer and then every command received by the master will be re-issued in the telnet session.
  • Slaves are able to automatically reconnect when the master <-> slave link goes down for some reason. If the master receives multiple concurrent slave synchronization requests, it performs a single background save in order to serve all of them.
  • When a master and a slave reconnects after the link went down, a full re-sync is always performed. However starting with Redis 2.8, a partial re-synchronization is also possible.

 

In order to configure the replication, all you have to do is to add the line below (or issue the same as a CLI command from slave) to the redis.conf file of the slave.

  • SLAVEOF <master_ip> <master_port>             (ex. SLAVEOF 127.0.0.1 6379)

 

to tune the replication process you can play with following options in the redis.conf file:

  • requirepass <password> – Require clients to issue AUTH <PASSWORD> before processing any other commands. This might be useful in environments in which you do not trust (eg. don’t run your own servers) others with access to the host running redis-server
  • masterauth <master-password> – If the master is password protected (using the “requirepass” configuration directive above) it is possible to tell the slave to authenticate before starting the replication synchronization process, otherwise the master will refuse the slave request
  • slave-serve-stale-data <yes|no> – When a slave loses its connection with the master, or when the replication is still in progress, the slave can act in two different ways:
    • still reply to client requests, possibly with out-of-date data (the default behavior if the switch is set to “yes”)
    • or reply with an error “SYNC with master in progress” to all the kind of commands, except for to INFO and SLAVEOF (otherwise)
  • slave-read-only <yes|no> – You can configure a slave instance to accept writes or not. Writing against a slave instance may be useful to store some ephemeral data (because data written on a slave will be easily deleted after re-sync with the master anyway), but may also cause problems if clients are writing to it because of a misconfiguration
  • repl-ping-slave-period <seconds> – Slaves send PINGs to server in a predefined interval. It’s possible to change this interval with the repl_ping_slave_period option from CLI. The default value is 10 seconds.
  • repl-timeout <seconds> – This option sets a timeout for both Bulk transfer I/O timeout and master data or ping response timeout. The default value is 60 seconds. It is important to make sure that this value is greater than the value specified for repl-ping-slave-period otherwise a timeout will be detected every time there is low traffic between the master and the slave.
  • repl-disable-tcp-nodelay <yes|no> – Controls whether to disable TCP_NODELAY on the slave socket after SYNC. If you select “yes” Redis will use a smaller number of TCP packets and less bandwidth to send data to slaves. But this can add a delay for the data to appear on the slave side, up to 40 milliseconds with Linux kernels using a default configuration. If you select “no” the delay for data to appear on the slave side will be reduced but more bandwidth will be used for replication. Default value of “no” is an optimization for low latency, but in very high traffic conditions or when the master and slaves are many hops away, turning this to “yes” may be a good idea.
  • slave-priority <integer> – The slave priority is an integer number published by Redis in the INFO output. It is used by Redis Sentinel in order to select a slave to promote into a master if the master is no longer working correctly. A slave with a low priority number is considered better for promotion, so for instance if there are three slaves with priority 10, 100, 25 Sentinel will pick the one with priority 10, that is the lowest. However a special priority of 0 marks the slave as not able to perform the role of master, so a slave with priority of 0 will never be selected by Redis Sentinel for promotion.

 

Allowing writes only with N attached replicas (redis.io):

  • Starting with Redis 2.8 it is possible to configure a Redis master in order to accept write queries only if at least N slaves are currently connected to the master, in order to improve data safety.
  • However because Redis uses asynchronous replication it is not possible to ensure the write actually received a given write, so there is always a window for data loss.
  • This is how the feature works:
    • Redis slaves ping the master every second, acknowledging the amount of replication stream processed.
    • Redis masters will remember the last time it received a ping from every slave.
    • The user can configure a minimum number of slaves that have a lag not greater than a maximum number of seconds.
    • If there are at least N slaves, with a lag less than M seconds, then the write will be accepted.
  • There are two configuration parameters for this feature:
    • min-slaves-to-write <number of slaves>
    • min-slaves-max-lag <number of seconds>

 

Have a nice weekend!

Advertisements

Redis Persistence

In my today’s post i’d like to touch on Redis persistence mechanisms.

 

What we can choose from are basically two options (or the combination of those):

  • The RDB persistence – which performs point-in-time snapshots of your dataset at specified intervals.
  • The AOF (append-only file) persistence – which logs every write operation received by the server, that can later be “played” again at server startup, reconstructing the original dataset (commands are logged using the same format as the Redis protocol itself).

 

Both of those options are controlled by two different groups of configuration settings in the redis.conf file:

  • RDB persistence:
    • save <seconds> <changes> – saving the DB on disk – the command will save the DB if both the given number of seconds and the given number of write operations against the DB occurred. You can have multiple save configurations “stacked” one after another, handling saves in different “seconds/changes” scenarios or you can disable saving at all commenting out all the “save” lines.
    • stop-writes-on-bgsave-error <yes|no> – by default Redis will stop accepting writes if RDB snapshots are enabled (at least one save point) and the latest background save failed. This will make the user aware (in an hard way) that data is not persisting on disk properly. If the background saving process will start working again Redis will automatically allow writes again.
    • rdbcompression <yes|no> – compression of string objects using LZF when dump .rdb databases.
    • rdbchecksum <yes|no> – since version 5 of RDB a CRC64 checksum is placed at the end of the file which makes the format more resistant to corruption but there is a performance hit to pay (around 10%) when saving and loading RDB files.
    • dbfilename <name> – The filename (default dump.rdb) where to dump the DB.
    • dir <path> – The working directory (default value is ./) where the DB will be written. The Append Only File will also be created inside this directory
  • AOF persistence:
    • appendonly <yes|no> – controls whether AOF mode should be turned on. By default Redis asynchronously

      dumps the dataset on disk (RDB Persistence) which is a mode good enough in many applications, but an issue with the Redis process or 

      a power outage may result into a few minutes of writes lost (depending on 

      the configured save points). AOF provides much better durability. Using the default data 

      fsync policy Redis can lose just one second of writes in a dramatic event like a server power outage, 

      or a single write if something wrong with the Redis process itself happens, but the operating system 

      is still running correctly. AOF and RDB persistence can be enabled at the same and they play very nicely

      together. If the AOF is enabled on startup Redis will load the AOF, that is the file with the better 

      durability guarantees.

    • appendfilename <name> – The name of the append only file (default: “appendonly.aof”)
    • appendfsync <mode> – mode in which fsync should operate. The fsync() call tells the Operating System to actually write data on disk 

      instead to wait for more data in the output buffer. Some OS will really flush 

      data on disk, some other OS will just try to do it ASAP. Redis supports three different modes:

      • <no>: don’t fsync, just let the OS flush the data when it wants. Faster.
      • <always>: fsync after every write to the append only log . Slow, Safest.
      • <everysec>: fsync only one time every second. Compromise. (default)
    • no-appendfsync-on-rewrite <yes|no> – when the AOF fsync policy is set to always or everysec, and a 

      background saving process (a background save or AOF log background rewriting) is 

      performing a lot of I/O against the disk, in some Linux configurations R

      edis may block too long on the fsync() call. In order to mitigate this problem it’s possible to use this option 

      which will prevent fsync() from being called in the main process while a BGSAVE or BGREWRITEAOF is in progress. 

      In practical terms, this means that it is 

      possible to lose up to 30 seconds of log in the worst scenario (with the default 

      Linux settings).

    • auto-aof-rewrite-percentage <percentage> and auto-aof-rewrite-min-size <size> – are both related to automatic rewrite of the append only file. Redis is able to automatically rewrite the log file (implicitly calling BGREWRITEAOF) when the AOF log size grows by the specified percentage. This is how it works: Redis remembers the size of the AOF file after the latest rewrite (if no rewrite has happened since the restart, the size of the AOF at startup is used). This base size is compared to the current size. If the current size is bigger than the specified percentage, the rewrite is triggered. Also you need to specify a minimal size for the AOF file to be rewritten, this is useful to avoid rewriting the AOF file even if the percentage increase is reached but it is still pretty small. Specify a percentage of zero in order to disable the automatic AOF rewrite feature.

 

Advantages and disadvantages of both methods (redis.io):

  • RDB advantages
    • RDB is a very compact single-file point-in-time representation of your Redis data. RDB files are perfect for backups. For instance you may want to archive your RDB files every hour for the latest 24 hours, and to save an RDB snapshot every day for 30 days. This allows you to easily restore different versions of the data set in case of disasters.
    • RDB is very good for disaster recovery, being a single compact file can be transfered to far data centers, or on Amazon S3 (possibly encrypted).
    • RDB maximizes Redis performances since the only work the Redis parent process needs to do in order to persist is forking a child that will do all the rest. The parent instance will never perform disk I/O or alike.
    • RDB allows faster restarts with big datasets compared to AOF.
  • RDB disadvantages
    • RDB is NOT good if you need to minimize the chance of data loss in case Redis stops working (for example after a power outage). You can configure different save points where an RDB is produced (for instance after at least five minutes and 100 writes against the data set, but you can have multiple save points). However you’ll usually create an RDB snapshot every five minutes or more, so in case of Redis stopping working without a correct shutdown for any reason you should be prepared to lose the latest minutes of data.
    • RDB needs to fork() often in order to persist on disk using a child process. Fork() can be time consuming if the dataset is big, and may result in Redis to stop serving clients for some millisecond or even for one second if the dataset is very big and the CPU performance not great. AOF also needs to fork() but you can tune how often you want to rewrite your logs without any trade-off on durability.
  • AOF advantages
    • Using AOF Redis is much more durable: you can have different fsync policies: no fsync at all, fsync every second, fsync at every query. With the default policy of fsync every second write performances are still great (fsync is performed using a background thread and the main thread will try hard to perform writes when no fsync is in progress.) but you can only lose one second worth of writes.
    • The AOF log is an append only log, so there are no seeks, nor corruption problems if there is a power outage. Even if the log ends with an half-written command for some reason (disk full or other reasons) the redis-check-aof tool is able to fix it easily.
    • Redis is able to automatically rewrite the AOF in background when it gets too big. The rewrite is completely safe as while Redis continues appending to the old file, a completely new one is produced with the minimal set of operations needed to create the current data set, and once this second file is ready Redis switches the two and starts appending to the new one.
    • AOF contains a log of all the operations one after the other in an easy to understand and parse format. You can even easily export an AOF file. For instance even if you flushed everything for an error using a FLUSHALL command, if no rewrite of the log was performed in the meantime you can still save your data set just stopping the server, removing the latest command, and restarting Redis again.
  • AOF disadvantages
    • AOF files are usually bigger than the equivalent RDB files for the same dataset.
    • AOF can be slower then RDB depending on the exact fsync policy. In general with fsync set to every second performances are still very high, and with fsync disabled it should be exactly as fast as RDB even under high load. Still RDB is able to provide more guarantees about the maximum latency even in the case of an huge write load.
    • Redis AOF works incrementally updating an existing state, like MySQL or MongoDB does, while the RDB snapshotting creates everything from scratch again and again, that is conceptually more robust.

 

The general advice from Redis team is that you should use both persistence methods if you want a degree of data safety comparable to what PostgreSQL can provide you.

 

 

Take care!

 

Resources:

JSON Activity Streams 1.0

In this post i’d like to address the subject of Activity Streams spec., something I’ve been working with recently in one of the projects.

 

Let’s start with a definition of an activity stream (Wikipedia):

  • An activity stream is a list of recent activities performed by an individual, typically on a single website. For example, Facebook’s News Feed is an activity stream. Since the introduction of the News Feed on September 6, 2006, other major websites have introduced similar implementations for their own users. Since the proliferation of activity streams on websites, there have been calls to standardize the format so that websites could interact with a stream provided by another website. The Activity Streams project, for example, is an effort to develop an activity stream protocol to syndicate activities across social Web applications. Several major websites with activity stream implementations have already opened up their activity streams to developers to use, including Facebook and MySpace. Though activity stream arises from social networking, nowadays it has become an essential part of business software. Enterprise social software is used in different types of companies to organize their internal communication and acts as an important addition to traditional corporate intranet.”

 

Activity Streams is an open format specification for activity stream protocols, which are used to syndicate activities taken in social web applications and services.

 

JSON Activity Streams 1.0 is the name of the specification published on May 2011 by the working group consisting of: J. Snell (IBM), M. Atkins (SAY Media), W. Norris (Google), C. Messina (Citizen Agency, Google), M. Wilkinson (MySpace, Facebook, VMware), R. Dolin (Microsoft).

 

On the homepage of the specification activitystrea.ms you’ll find more details including a list of early adopters (BBC, GnipGoogle, BuzzGowallaIBMMySpaceOperaSocialcastSuperfeedr,
TypePadWindows LiveYIID, and many others).

 

Introduction:

  • In its simplest form, an activity consists of an actor, a verb, an an object, and a target.
  • It tells the story of a person performing an action on or with an object — “Geraldine posted a photo to her album” or “John shared a video”. In most cases these components will be explicit, but they may also be implied.
  • Goal of the specification is to provide sufficient metadata about an activity such that a consumer of the data can present it to a user in a rich human-friendly format. (this may include constructing readable sentences about the activity that occurred, visual representations of the activity, or combining similar activities for display).
  • The basic properties that comprise the description of an activity are defined in the appropriate sections of the specification.
  • Within the specification, an object is a thing, real or imaginary, which participates in an activity. It may be the entity performing the activity, or the entity on which the activity was performed.
  • An object consists of properties defined in appropriate sections of the specification. Certain object types may further refine the meaning of these properties, or they may define additional properties.
  • Some types of objects may have an alternative visual representation in the form of an image, video or embedded HTML fragments. A Media Link represents a hyperlink to such resources.
  • An Activity Stream is a collection one or more individual activities. The relationship between the activities within the collection is undefined by this specification.

 

Following is a simple, minimal example of a JSON serialized activity:

{
    "published": "2011-02-10T15:04:55Z",
    "actor": {
        "url": "http://example.org/martin",
        "objectType" : "person",
        "id": "tag:example.org,2011:martin",
        "image": {
            "url": "http://example.org/martin/image",
            "width": 250,
            "height": 250
        },
        "displayName": "Martin Smith"
    },
    "verb": "post",
    "object" : {
        "url": "http://example.org/blog/2011/02/entry",
        "id": "tag:example.org,2011:abc123/xyz"
    },
    "target" : {
        "url": "http://example.org/blog/",
        "objectType": "blog",
        "id": "tag:example.org,2011:abc123",
        "displayName": "Martin's Blog"
    }
}

 

To give you an idea on the “breadth” of the spec., and how many various activities got its individual verb, take a look at the following complete list of “verbs”:

  • accept – Indicates that that the actor has accepted the object. For instance, a person accepting an award, or accepting an assignment.
  • access – Indicates that the actor has accessed the object. For instance, a person accessing a room, or accessing a file.
  • acknowledge – Indicates that the actor has acknowledged the object. This effectively signals that the actor is aware of the object’s existence.
  • add – Indicates that the actor has added the object to the target. For instance, adding a photo to an album.
  • agree – Indicates that the actor agrees with the object. For example, a person agreeing with an argument, or expressing agreement with a particular issue.
  • append – Indicates that the actor has appended the object to the target. For instance, a person appending a new record to a database.
  • approve – Indicates that the actor has approved the object. For instance, a manager might approve a travel request.
  • archive – Indicates that the actor has archived the object.
  • assign – Indicates that the actor has assigned the object to the target.
  • at – Indicates that the actor is currently located at the object. For instance, a person being at a specific physical location.
  • attach – Indicates that the actor has attached the object to the target.For instance, a person attaching a file to a wiki page or an email.
  • attend – Indicates that the actor has attended the object. For instance, a person attending a meeting.
  • author – Indicates that the actor has authored the object. Note that this is a more specific form of the verb “create”.
  • authorize – Indicates that the actor has authorized the object. If a target is specified, it means that the authorization is specifically in regards to the target. For instance, a service can authorize a person to access a given application; in which case the actor is the service, the object is the person, and the target is the application. In contrast, a person can authorize a request; in which case the actor is the person and the object is the request and there might be no explicit target.
  • borrow – Indicates that the actor has borrowed the object. If a target is specified, it identifies the entity from which the object was borrowed. For instance, if a person borrows a book from a library, the person is the actor, the book is the object and the library is the target.
  • build – Indicates that the actor has built the object. For example, if a person builds a model or compiles code.
  • cancel – Indicates that the actor has canceled the object. For instance, canceling a calendar event.
  • close – Indicates that the actor has closed the object. For instance, the object could represent a ticket being tracked in an issue management system.
  • complete – Indicates that the actor has completed the object.
  • confirm – Indicates that the actor has confirmed or agrees with the object. For instance, a software developer might confirm an issue reported against a product.
  • consume – Indicates that the actor has consumed the object. The specific meaning is dependent largely on the object’s type. For instance, an actor may “consume” an audio object, indicating that the actor has listened to it; or an actor may “consume” a book, indicating that the book has been read. As such, the “consume” verb is a more generic form of other more specific verbs such as “read” and “play”.
  • checkin – Indicates that the actor has checked-in to the object. For instance, a person checking-in to a Place.
  • create – Indicates that the actor has created the object.
  • delete – Indicates that the actor has deleted the object. This implies, but does not require, the permanent destruction of the object.
  • deliver – Indicates that the actor has delivered the object. For example, delivering a package.
  • deny – Indicates that the actor has denied the object. For example, a manager may deny a travel request.
  • disagree – Indicates that the actor disagrees with the object.
  • dislike – Indicates that the actor dislikes the object. Note that the “dislike” verb is distinct from the “unlike” verb which assumes that the object had been previously “liked”.
  • experience – Indicates that the actor has experienced the object in some manner. Note that, depending on the specific object types used for both the actor and object, the meaning of this verb can overlap that of the “consume” and “play” verbs. For instance, a person might “experience” a movie; or “play” the movie; or “consume” the movie. The “experience” verb can be considered a more generic form of other more specific verbs as “consume”, “play”, “watch”, “listen”, and “read”
  • favorite – Indicates that the actor marked the object as an item of special interest.
  • find – Indicates that the actor has found the object.
  • flag-as-inappropriate – Indicates that the actor has flagged the object as being inappropriate for some reason. When using this verb, thecontext property can be used to provide additional detail about why the object has been flagged.
  • follow – Indicates that the actor began following the activity of the object. In most cases, the objectType will be a “person”, but it can potentially be of any type that can sensibly generate activity. Processors MAY ignore (silently drop) successive identical “follow” activities.
  • give – Indicates that the actor is giving an object to the target. Examples include one person giving abadge object to another person. Theobject identifies the object being given. Thetarget identifies the receiver.
  • host – Indicates that the actor is hosting the object. As in hosting an event, or hosting a service.
  • ignore – Indicates that the actor has ignored the object. For instance, this verb may be used when an actor has ignored a friend request, in which case the object may be the request-friend activity.
  • insert – Indicates that the actor has inserted the object into the target.
  • install – Indicates that the actor has installed the object, as in installing an application.
  • interact – Indicates that the actor has interacted with the object. For instance, when one person interacts with another.
  • invite – Indicates that the actor has invited the object, typically a person object, to join or participate in the object described by the target. The target could, for instance, be an event, group or a service.
  • join – Indicates that the actor has become a member of the object. This specification only defines the meaning of this verb when theobject of the Activity has an objectTypeof group, though implementors need to be prepared to handle other types of objects.
  • leave – Indicates that the actor has left the object. For instance, a Person leaving a Group or checking-out of a Place.
  • like – Indicates that the actor marked the object as an item of special interest. The “like” verb is considered to be an alias of “favorite”. The two verb are semantically identical.
  • listen – Indicates that the actor has listened to the object. This is typically only applicable for objects representing audio content, such as music, an audio-book, or a radio broadcast. The “listen” verb is a more specific form of the “consume”, “experience” and “play” verbs.
  • lose – Indicates that the actor has lost the object. For instance, if a person loses a game.
  • make-friend – Indicates the creation of a friendship that is reciprocated by the object. Since this verb implies an activity on the part of its object, processors MUST NOT accept activities with this verb unless they are able to verify through some external means that there is in fact a reciprocated connection. For example, a processor may have received a guarantee from a particular publisher that the publisher will only use this Verb in cases where a reciprocal relationship exists.
  • open – Indicates that the actor has opened the object. For instance, the object could represent a ticket being tracked in an issue management system.
  • play – Indicates that the actor spent some time enjoying the object. For example, if the object is a video this indicates that the subject watched all or part of the video. The “play” verb is a more specific form of the “consume” verb.
  • present – Indicates that the actor has presented the object. For instance, when a person gives a presentation at a conference.
  • purchase – Indicates that the actor has purchased the object. If a target is specified, in indicates the entity from which the object was purchased.
  • qualify – Indicates that the actor has qualified for the object. If a target is specified, it indicates the context within which the qualification applies.
  • read – Indicates that the actor read the object. This is typically only applicable for objects representing printed or written content, such as a book, a message or a comment. The “read” verb is a more specific form of the “consume”, “experience” and “play” verbs.
  • receive – Indicates that the actor is receiving an object. Examples include a person receiving abadge object. Theobject identifies the object being received.
  • reject – Indicates that the actor has rejected the object.
  • remove – Indicates that the actor has removed the object from the target.
  • remove-friend – Indicates that the actor has removed the object from the collection of friends.
  • replace – Indicates that the actor has replaced the target with the object.
  • request – Indicates that the actor has requested the object. If a target is specified, it indicates the entity from which the object is being requested.
  • request-friend – Indicates the creation of a friendship that has not yet been reciprocated by the object.
  • resolve – Indicates that the actor has resolved the object. For instance, the object could represent a ticket being tracked in an issue management system.
  • return – Indicates that the actor has returned the object. If a target is specified, it indicates the entity to which the object was returned.
  • retract – Indicates that the actor has retracted the object. For instance, if an actor wishes to retract a previously published activity, the object would be the previously published activity that is being retracted.
  • rsvp-maybe – The “possible RSVP” verb indicates that the actor has made a possible RSVP for the object. This specification only defines the meaning of this verb when its object is an event, though implementors need to be prepared to handle other object types. The use of this verb is only appropriate when the RSVP was created by an explicit action by the actor. It is not appropriate to use this verb when a user has been added as an attendee by an event organiser or administrator.
  • rsvp-no – The “negative RSVP” verb indicates that the actor has made a negative RSVP for the object. This specification only defines the meaning of this verb when its object is an event, though implementors need to be prepared to handle other object types. The use of this verb is only appropriate when the RSVP was created by an explicit action by the actor. It is not appropriate to use this verb when a user has been added as an attendee by an event organiser or administrator.
  • rsvp-yes – The “positive RSVP” verb indicates that the actor has made a positive RSVP for an object. This specification only defines the meaning of this verb when its object is an event, though implementors need to be prepared to handle other object types. The use of this verb is only appropriate when the RSVP was created by an explicit action by the actor. It is not appropriate to use this verb when a user has been added as an attendee by an event organiser or administrator.
  • satisfy – Indicates that the actor has satisfied the object. If a target is specified, it indicate the context within which the object was satisfied. For instance, if a person satisfies the requirements for a particular challenge, the person is the actor; the requirement is the object; and the challenge is the target.
  • save – Indicates that the actor has called out the object as being of interest primarily to him- or herself. Though this action MAY be shared publicly, the implication is that the object has been saved primarily for the actor’s own benefit rather than to show it to others as would be indicated by the “share” verb.
  • schedule – Indicates that the actor has scheduled the object. For instance, scheduling a meeting.
  • search – Indicates that the actor is or has searched for the object. If a target is specified, it indicates the context within which the search is or has been conducted.
  • sell – Indicates that the actor has sold the object. If a target is specified, it indicates the entity to which the object was sold.
  • send – Indicates that the actor has sent the object. If a target is specified, it indicates the entity to which the object was sent.
  • share – Indicates that the actor has called out the object to readers. In most cases, the actor did not create the object being shared, but is instead drawing attention to it.
  • sponsor – Indicates that the actor has sponsored the object. If a target is specified, it indicates the context within which the sponsorship is offered. For instance, a company can sponsor an event; or an individual can sponsor a project; etc.
  • start – Indicates that the actor has started the object. For instance, when a person starts a project.
  • stop-following – Indicates that the actor has stopped following the object.
  • submit – Indicates that the actor has submitted the object. If a target is specified, it indicates the entity to which the object was submitted.
  • tag – Indicates that the actor has associated the object with the target. For example, if the actor specifies that a particular user appears in a photo. the object is the user and the target is the photo.
  • terminate – Indicates that the actor has terminated the object.
  • tie – Indicates that the actor has neither won or lost the object. This verb is generally only applicable when the object represents some form of competition, such as a game.
  • unfavorite – Indicates that the actor has removed the object from the collection of favorited items.
  • unlike – Indicates that the actor has removed the object from the collection of liked items.
  • unsatisfy – Indicates that the actor has not satisfied the object. If a target is specified, it indicates the context within which the object was not satisfied. For instance, if a person fails to satisfy the requirements of some particular challenge, the person is the actor; the requirement is the object and the challenge is the target.
  • unsave – Indicates that the actor has removed the object from the collection of saved items.
  • unshare – Indicates that the actor is no longer sharing the object. If a target is specified, it indicates the entity with whom the object is no longer being shared.
  • update – The “update” verb indicates that the actor has modified the object. Use of the “update” verb is generally reserved to indicate modifications to existing objects or data such as changing an existing user’s profile information.
  • use – Indicates that the actor has used the object in some manner.
  • watch – Indicates that the actor has watched the object. This verb is typically applicable only when the object represents dynamic, visible content such as a movie, a television show or a public performance. This verb is a more specific form of the verbs “experience”, “play” and “consume”.
  • win – Indicates that the actor has won the object. This verb is typically applicable only when the object represents some form of competition, such as a game.

 

The complete schema can be found on the Github page of the project, here.

 

Take care!

 

 

Resources:

Redis data sharding – part 2 – hash-based keys

In my previous post on Redis data sharding i introduced the concept of data sharding/partitioning and provided a small Java code example to illustrate the idea. As you noticed i was creating fixed-size “emailbuckets”, containing 1024 emails each. An email address was the key of my hash, while user id was the value. For a shard identifier i used a simple integer value (shardKey) obtained as a result of “i mod shardSize” operation.

Whereas such approach illustrates the concept well, it’s impractical in “real life” applications. This is due to a simple reason – knowing the email address alone (which may often be the only thing you’d know at some point of the app execution flow; for example when you’re using Spring Security and requesting emails “as usernames” during sign-in process), you wouldn’t be able to retrieve the corresponding userId. If you would know the algorithm by which shardKey was generated, in this case – yes – you would be able to traverse emailbuckets one-by-one looking for the appropriate email, but without that knowledge you wouldn’t be able to tell which shard the email address you’re looking for, ended up in.

One solution to that problem is to use a different key for sharding data; something that is computed directly based on the data you’re interested in partitioning. An obvious candidate here is the email address itself. If you’d be able to generate shardKey based on email address you could reproduce the same scenario every time a user provides you with his email during signing in and retrieve his userId (which you could use later on (for example) to further query another hash in Redis – “users:id” – that stores complete user profile).

 

This seems like an ideal task for a hash function… Let’s start first with some background on hashing. According to Neil Coffey’s Javamex article Introduction to hashing:

  • Hashing means using some function or algorithm to map object data (eg. content of a String object) to some representative integer value. This so-called hash code (or simply hash) can then be used as a way to narrow down our search when looking for the item…

 

Also, when you search Wikipedia after Java hashCode() function, you’ll get the following definition:

  • In the Java programming language, every class must provide a hashCode() method which digests the data stored in an instance of the class into a single hash value (a 32-bit signed integer). This hash is used by other code when storing or manipulating the instance – the values are intended to be evenly distributed for varied inputs in order to use in clustering. This property is important to the performance of hash tables and other data structures that store objects in groups (“buckets”) based on their computed hash values.

 

Looks like this is exactly what we’re interested in – …evenly distributed values for varied inputs…, which …is important to the performance of data structures that store objects in groups (shards in our case) based on their computed hash values.

Conclusion: Java hashCode() function is what we’ll proceed with.

 

More from Wikipedia on Java hashCode():

  • Starting with Java version 1.2, the java.lang.String class implements its hashCode() using a product sum algorithm over the entire text of the string.
  • An instance s of the java.lang.String class, would have a hash code h(s) defined by:
    Java String hashCode()

     

  • where terms are summed using Java 32-bit int addition, s[i] denotes the i-th character of the string, and n is the length of s.

 

Now, looking at Java docs on String.hashCode() function we can read:

  • The hash code for a String object is computed as
    s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1]

     

  • using int arithmetic, where s[i] is the ith character of the string, n is the length of the string, and ^ indicates exponentiation. (The hash value of the empty string is zero.)

 

Finally let’s take a look at some Java code of String object showing how hashCode() has actually been implemented:

public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}

 

An alternative (faster) implementation may look like this (from Apache Harmony JDK):

public int hashCode() {
    if (hashCode == 0) {
        int hash = 0, multiplier = 1;
        for (int i = offset + count - 1; i >= offset; i--) {
            hash += value[i] * multiplier;
            int shifted = multiplier << 5;
            multiplier = shifted - multiplier;
        }
        hashCode = hash;
    }
    return hashCode;
}

what’s the difference between the two above code snippets? As you can see, multiplication can be replaced by a bitwise shift operation and a subtraction for better performance. “(multiplier << 5) – multiplier” is just 31*multiplier after all (however VMs nowadays do this optimization automatically). If you’re interested in good reading on the subject of Binary numbers i strongly recommend Neil Coffey’s Javamex article: Introduction to binary numbers.

 

OK, applying all this knowledge to our sharding code example results in the following implementation:

while(i<1000000) {
    String userId = String.valueOf(i++);
    String emailAddress = String.format("user_%s@mariuszprzydatek.com", userId);
    int shardKey = emailAddress.hashCode();
    redisTemplate.opsForHash().put(String.format("emailsbucket:%s", shardKey), emailAddress, userId);
}

 

Happy coding! 🙂

 

 

Resources:

Spring REST API hardening – exceptions handling

For some time now there’s a lot of discussion over the internet on the definition of a unified RESTful API standard (architecture, design, interfaces, etc.). RFC’s are being discussed by IETF committees trying to come up with a standard, work continues on re-designing the HTTP protocol itself (HTTPbis, by the IETF HTTPbis WG chaired by Mark Nottingham), but what we have thus far are only good and bad practices…

 

What i’d like to address in this post are good practices related to exceptions handling in a Java Spring MVC based RESTful API application.

 

Let’s start with this: In order to make your REST API more developer-friendly, you may want your MVC controllers to return (within the body of the response), some information that can assist the client developer while using your API.

 

Using a JSON data format, a sample controller response in situation of an exception may look like this:

{
    "code" : "SAE00202",
    "status" : "SECURITY_AUTHORITY_ERROR",
    "errors" : [ "Security Exception: Insufficient Authorization Level. Access denied" ]
}

 

Here’s an example of how you can achieve that easily using Spring MVC’s @ControllerAdvice annotation (which indicates the annotated class assists a “Controller” and serves as a specialization of @Component annotation, allowing implementation classes to be auto-detected through classpath scanning).

@ControllerAdvice
public class BusinessExceptionHandler extends DefaultExceptionHandler {

    @ExceptionHandler(IncompleteUserProfileException.class)
    @ResponseStatus(value = HttpStatus.PRECONDITION_FAILED)
    @ResponseBody DefaultErrorMessage handleIncompleteUserProfileException(IncompleteUserProfileException e) {

        if(debug) logException(e);

        String error = getResourceBundle().getMessage("exception.user.profile.incomplete", null, Locale.getDefault());

        return new DefaultErrorMessage("RS00302", "BUSINESS_ERROR", error);

    }

}

 

Aside from the fact that you may want to write custom handlers like the one above for your application-specific exceptions (Business/Security/Validation related, etc.), you may also want to “go deeper” and extend the ResponseEntityExceptionHandler class (abstract), and override the default implementation of the exceptions below; thrown usually by MVC Controllers:

Spring MVC ResponseEntityExceptionHandler Exceptions

 

In order to do that, first you have to start with a simple POJO representing your default error message:

public class DefaultErrorMessage {
    private String code;
    private String status;
    private List errors = new ArrayList<>();

    public DefaultErrorMessage(String code, String status, String error) {
        this.code = code;
        this.status = status;
        this.errors.add(error);
    }

    public DefaultErrorMessage(String code, String status, List errors) {
        this.code = code;
        this.status = status;
        this.errors = errors;
    }

    // getters and setters omitted
}

 

Having this in place, a custom implementation of BindException may look like this:

@ControllerAdvice
public class CustomResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {

    @Override
    protected ResponseEntity<Object> handleBindException(BindException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

        List<String> errors = new ArrayList<>(ex.getAllErrors().size());
        List<FieldError> fieldErrors = ex.getFieldErrors();
        StringBuilder sb;

        for (FieldError fieldError : fieldErrors) {
            sb = new StringBuilder();
            sb.append("Field: ").append(fieldError.getField()).append(", ");
            sb.append("Value: ").append(fieldError.getRejectedValue()).append(", ");
            sb.append("Message: ").append(fieldError.getDefaultMessage());
            errors.add(sb.toString());
        }

        List<ObjectError> globalErrors = ex.getGlobalErrors();

        for (ObjectError objectError : globalErrors) {
            sb = new StringBuilder();
            sb.append("Object: ").append(objectError.getObjectName()).append(", ");
            sb.append("Code: ").append(objectError.getCode()).append(", ");
            sb.append("Message: ").append(objectError.getDefaultMessage());
            errors.add(sb.toString());
        }

        DefaultErrorMessage errorMessage = new DefaultErrorMessage("RQ00051", "RQ_BODY_VALIDATION_ERROR", errors);
        return new ResponseEntity(errorMessage, headers, status);

    }

}

 

I think you see the direction it’s heading in…

 

Happy coding 🙂

Cheers!

 

 

Resources:

Redis data sharding – part 1

In one of my previous posts on Redis i provided a definition of data sharding, quoting a great book “Redis in Action” authored by Dr. Josiah L Carlson:

  • “Sharding is a method by which you partition your data into different pieces. In this case, you partition your data based on IDs embedded in the keys, based on the hash of keys, or some combination of the two. Through partitioning your data, you can store and fetch the data from multiple machines, which can allow a linear scaling in performance for certain problem domains.”

 

Today i’d like to elaborate some more on data sharding based on IDs embedded in the keys.

 

Let’s start with an example of a hypothetical data stored in an Redis instance:

redis 127.0.0.1:6379>keys *
(empty list or set)
redis 127.0.0.1:6379>set emails:1 me@mariuszprzydatek.com
OK
redis 127.0.0.1:6379>get emails:1
"me@mariuszprzydatek.com"

what i did here is to use the basic String data type to store an email of a user. As you can see, i embedded user id within the key (’emails:1′). Now, if a front-end application would ask for an email address of a user with id=1, on the back-end side i would concatenate the keyword which i usually use to denote keys i store emails under (ie. ’emails’) with the id of a user (‘1’), add a colon (‘:’) in between, and this way i’ll get the resulting key (’emails:1′) i should look after while making a call to the Redis instance.

 

This solution is nice but if i’ll have 1 million of users registered in my system and use Redis as the data store for keeping mappings between identifier of a user and his email, i will end up with 1 million keys (’emails:1′, ’emails:2′, ’emails:3′, etc.). This is a volume my Redis instance will easily handle (see my previous post on Redis Performance Basics) and it will use little more than 190MB to store everything in the memory (so much due to a lot of overhead when storing small keys and values; the ratio is much better with large keys/values), but this is only one attribute we’re talking about – and what about firstName, lastName, etc.?. Obviously, if my system will have millions of registered users and i’d use Redis as my primary data store for users-related info, i would be running multiple instances of Redis already and based on the id of a user, route the queries to a specific instance, but there’s still a lot we can do to optimize costs prior to thinking about scaling.

 

Small code snippet to generate 1M of emails stored in Redis using String data structure (and Spring Data Redis mentioned in my other post).

int i = 0;
while(i<1000000) {
    redisTemplate.opsForValue().set(String.format("emails:%s", i++), "me@mariuszprzydatek.com");
}

the loop above executes in 2 mins on my Windows 8 64bit i7 laptop and the ‘redis-server’ process allocates ca 190 MB of memory.

 

Now, what will happen if we change the data structure let’s say to a Redis Hash?

Next code snippet and we’re getting just that:

int i = 0;
while(i<1000000) {
    String userId = String.valueOf(i++);
    String emailAddress = String.format("user_%s@mariuszprzydatek.com", userId);
    redisTemplate.opsForHash().put("emails", emailAddress, userId)
}

2 mins and 165 MB of memory allocated – a 15 % gain absolutely for free.

 

Let’s try with data sharding/partitioning. Another code snippet using Redis Hash data structure and there you go:

int shardSize = 1024;
int i = 0;
while(i<1000000) {
    int shardKey = i/shardSize;
    String userId = String.valueOf(i++);
    String emailAddress = String.format("user_%s@mariuszprzydatek.com", userId);
    redisTemplate.opsForHash().put(String.format("emailsbucket:%s", shardKey), emailAddress, userId);
}

2 mins later and… only 30 MB allocated – now you’re talking Mariusz!

Staggering 530 % increase in memory allocation efficiency!

 

Hope you enjoyed the first part of this brief tutorial.

 

Cheers!

 

 

Resources:

Spring Data Redis overview

If you are, like me, a great fan of the Spring Framework, you probably know already the Spring Data product and corresponding spring-data-redis module. If not, let me introduce this wonderful tool in this brief post.

 

Spring Data Redis offers the following features (copied from the product homepage):

  • Connection package as low-level abstraction across multiple Redis drivers/connectors (Jedis,  JRedisLettuceSRP and RJC)
  • Exception translation to Spring’s portable Data Access exception hierarchy for Redis driver exceptions
  • RedisTemplate that provides a high level abstraction for performing various redis operations, exception translation and serialization support
  • Pubsub support (such as a MessageListenerContainer for message-driven POJOs)
  • JDK, String, JSON and Spring Object/XML mapping serializers
  • JDK Collection implementations on top of Redis
  • Atomic counter support classes
  • Sorting and Pipelining functionality
  • Dedicated support for SORT, SORT/GET pattern and returned bulk values
  • Redis implementation for Spring 3.1 cache abstraction

 

As of the time of writing this post, the latest product release is labeled ‘1.0.6.RELEASE’, and available as a Maven dependency:

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>1.0.6.RELEASE</version>
</dependency>

 

Using Spring Data Redis in your project is as easy as defining the above dependency in your master pom.xml file, and configuring the RedisTemplate bean in either xml context file (example below) or using Java configuration:

    <context:property-placeholder location="classpath:redis.properties"/>

    <bean id="connectionFactory"
          class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
          p:hostName="${redis.host}"
          p:port="${redis.port}"
          p:password="${redis.pass}"
          p:usePool="${redis.pool}" />

    <bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer" />

    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
          p:connectionFactory-ref="connectionFactory"
          p:defaultSerializer-ref="stringRedisSerializer" />

 

and the corresponding redis.config file:

# Redis settings
redis.host=localhost
redis.port=6379
redis.pass=
redis.pool=true

 

…in code you’re using the RedisTemplate like this:

@Autowired
private RedisTemplate redisTemplate;

    public void saveEmail(String email, long userId) {
        redisTemplate.opsForHash().put("emails", String.valueOf(userId), email);
    }

 

I did also i quick overview of the extend to which Redis native API commands, related to performing operations on 5 basic Redis data types, have been implemented in the product. Below you’ll find a short visual summary:

 

  • Strings

Spring Data Redis String

 

 

  • Lists

Spring Data Redis List

 

 

  • Sets

Spring Data Redis Set

 

 

  • Hashes

Spring Data Redis Hash

 

 

  • ZSets

Spring Data Redis ZSet

 

 

Cheers!

 

 

 

Resources: