{"id":18264420,"url":"https://github.com/nozeio/redi-s","last_synced_at":"2025-06-29T18:04:48.017Z","repository":{"id":63919331,"uuid":"129256839","full_name":"NozeIO/redi-s","owner":"NozeIO","description":"A performant Redis server implemented in SwiftNIO.","archived":false,"fork":false,"pushed_at":"2024-01-29T23:27:17.000Z","size":101,"stargazers_count":85,"open_issues_count":17,"forks_count":0,"subscribers_count":2,"default_branch":"develop","last_synced_at":"2025-06-28T10:20:32.124Z","etag":null,"topics":["asyncio","redis","redis-server","swift-nio","swift-server"],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NozeIO.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-04-12T13:36:54.000Z","updated_at":"2025-06-01T10:58:28.000Z","dependencies_parsed_at":"2024-11-05T11:16:13.128Z","dependency_job_id":null,"html_url":"https://github.com/NozeIO/redi-s","commit_stats":{"total_commits":26,"total_committers":3,"mean_commits":8.666666666666666,"dds":"0.15384615384615385","last_synced_commit":"34c3bcd35ec65131462c749906381512cc551f4d"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/NozeIO/redi-s","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NozeIO%2Fredi-s","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NozeIO%2Fredi-s/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NozeIO%2Fredi-s/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NozeIO%2Fredi-s/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NozeIO","download_url":"https://codeload.github.com/NozeIO/redi-s/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NozeIO%2Fredi-s/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262642956,"owners_count":23341817,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asyncio","redis","redis-server","swift-nio","swift-server"],"created_at":"2024-11-05T11:14:36.173Z","updated_at":"2025-06-29T18:04:47.986Z","avatar_url":"https://github.com/NozeIO.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch2\u003eRedi/S\n  \u003cimg src=\"http://zeezide.com/img/redi-s-logo-286x100.png\"\n       align=\"right\" width=\"286\" height=\"100\" /\u003e\n\u003c/h2\u003e\n\n![Swift4](https://img.shields.io/badge/swift-4-blue.svg)\n![macOS](https://img.shields.io/badge/os-macOS-green.svg?style=flat)\n![tuxOS](https://img.shields.io/badge/os-tuxOS-green.svg?style=flat)\n![Travis](https://travis-ci.org/NozeIO/redi-s.svg?branch=develop)\n\nRedi/S is a **Redis server implementation** in the\n[Swift](https://swift.org)\nprogramming language.\nBased on Apple's \n[SwiftNIO](https://github.com/apple/swift-nio)\nframework.\n\nWhat is [Redis](https://redis.io)? Checkout the home page,\nbut it is an easy to use and very popular Key-Value Store,\nw/ PubSub functionality.\n\nIt is not meant to replace the C based [Redis](https://redis.io) server,\nbut the goal is to make it feature complete and well performing.\n\nUse cases:\n\n- Testing of server apps (pull up a Redi/S within your Xcode just for testing).\n- As an \"embedded\" database. Redi/S comes as a regular Swift package you can\n  directly embed into your own server or application.\n- Easy to extend in a safy language.\n\n\n## Supported Commands\n\nRedi/S supports a lot, including PubSub and monitoring.\u003cbr /\u003e\nRedi/S supports a lot *not*, including transactions or HyperLogLogs.\n\nThere is a [list of supported commands](Sources/RedisServer/Commands.md).\n\nContributions welcome!! A lot of the missing stuff is really easy to add!\n\n\n## Performance\n\nPerformance differs, e.g. lists are implemented using arrays (hence RPUSH is\nokayish, LPUSH is very slow).\nBut looking at just the simple GET/SET, it is surprisingly close to the\nhighly optimized C implementation.\n\n### 2024-01-30 Swift 5.9.2\n\nRedi/S (1 NIO thread on M1 Mac Mini):\n```\nhelge@M1ni ~ $ redis-benchmark -p 1337 -t SET,GET,RPUSH,INCR -n 500000 -q\nWARNING: Could not fetch server CONFIG\nSET: 163345.31 requests per second, p50=0.255 msec                    \nGET: 167336.02 requests per second, p50=0.239 msec                    \nINCR: 158780.56 requests per second, p50=0.239 msec                    \nRPUSH: 157480.31 requests per second, p50=0.271 msec                    \n```\n\nNote that more threads end up being worse. Not entirely sure why.\n\n### Those Are Older Numbers from 2018\n\n- using Swift 4.2 on Intel, IIRC\n\nRedi/S (2 NIO threads on MacPro 3,7 GHz Quad-Core Intel Xeon E5):\n```\nhelge@ZeaPro ~ $ redis-benchmark -p 1337 -t SET,GET,RPUSH,INCR -n 500000 -q\nSET: 48003.07 requests per second\nGET: 48459.00 requests per second\nINCR: 43890.45 requests per second\nRPUSH: 46087.20 requests per second\n```\n\nRedis 4.0.8  (same MacPro 3,7 GHz Quad-Core Intel Xeon E5):\n```\nhelge@ZeaPro ~ $ redis-benchmark -t SET,GET,RPUSH,INCR -n 500000 -q\nSET: 54884.74 requests per second\nGET: 54442.51 requests per second\nINCR: 54692.62 requests per second\nRPUSH: 54013.18 requests per second\n```\n\nRedi/S on RaspberryPi 3B+\n```\n$ redis-benchmark -h zpi3b.local -p 1337 -t SET,GET,RPUSH,INCR -n 50000 -q\nSET: 4119.29 requests per second\nGET: 5056.12 requests per second\nINCR: 3882.59 requests per second\nRPUSH: 3872.07 requests per second\n```\n\nThere are [Performance notes](Sources/RedisServer/Performance.md),\nlooking at the specific NIO implementation of Redi/S.\n\nPersistence is really inefficient,\nthe databases are just dumped as JSON via Codable.\nEasy to fix.\n\n\n## How to run\n\n```\n$ swift build -c release\n$ .build/release/redi-s\n2383:M 11 Apr 17:04:16.296 # sSZSsSZSsSZSs Redi/S is starting sSZSsSZSsSZSs\n2383:M 11 Apr 17:04:16.302 # Redi/S bits=64, pid=2383, just started\n2383:M 11 Apr 17:04:16.303 # Configuration loaded\n ____          _ _    ______\n |  _ \\ ___  __| (_)  / / ___|    Redi/S 64 bit\n | |_) / _ \\/ _` | | / /\\___ \\\n |  _ \u003c  __/ (_| | |/ /  ___) |   Port: 1337\n |_| \\_\\___|\\__,_|_/_/  |____/    PID: 2383\n\n2383:M 11 Apr 17:04:16.304 # Server initialized\n2383:M 11 Apr 17:04:16.305 * Ready to accept connections\n```\n\n## Status\n\nThere are a few inefficiencies, the worst being the persistent storage.\nYet generally this seems to work fine.\n\nThe implementation has grown a bit and could use a little refactoring,\nspecially the database dump parts.\n\n\n## Playing with the Server\n\nYou'd like to play with this, but never used Redis before?\nOK, a small tutorial on what you can do with it.\n\nFirst make sure the server runs in one shell:\n```\n$ swift build -c release\n$ .build/release/redi-s\n83904:M 12 Apr 16:33:15.159 # sSZSsSZSsSZSs Redi/S is starting sSZSsSZSsSZSs\n83904:M 12 Apr 16:33:15.169 # Redi/S bits=64, pid=83904, just started\n83904:M 12 Apr 16:33:15.170 # Configuration loaded\n ____          _ _    ______\n |  _ \\ ___  __| (_)  / / ___|    Redi/S 64 bit\n | |_) / _ \\/ _` | | / /\\___ \\\n |  _ \u003c  __/ (_| | |/ /  ___) |   Port: 1337\n |_| \\_\\___|\\__,_|_/_/  |____/    PID: 83904\n\n83904:M 12 Apr 16:33:15.176 # Server initialized\n83904:M 12 Apr 16:33:15.178 * Ready to accept connections\n```\n\nNotice how the server says: \"Port 1337\". This is the port the server is running\non.\n\n### Via telnet/netcat\n\nYou can directly connect to the server and issue Redis commands (the server\nis then running the connection in `telnet mode`, which is different to the\nregular RESP protocol):\n\n```\n$ nc localhost 1337\nKEYS *\n*0\nSET theanswer 42\n+OK\nGET theanswer\n$2\n42\n```\n\nRedis is a key/value store. That is, it acts like a big Dictionary that\ncan be modified from multiple processes. Above we list the available\n`KEYS`, then we set the key `theanswer` to the value 42, and retrieve it.\n(Redis provides [great documentation](https://redis.io/commands)\n on the available commands, Redi/S implements many, but not all of them).\n\n### Via redis-cli\n\nRedis provides a tool called `redis-cli`, which is a much more convenient\nway to access the server.\nOn macOS you can install that using `brew install redis` (which also gives\nyou the real server),\non Ubuntu you can grab it via `sudo apt-get install redis-tools`.\n\nThe same thing we did in `telnet` above:\n\n```\n$ redis-cli -p 1337\n127.0.0.1:1337\u003e KEYS *\n1) \"theanswer\"\n127.0.0.1:1337\u003e SET theanswer 42\nOK\n127.0.0.1:1337\u003e GET theanswer\n\"42\"\n```\n\n### Key Expiration\n\nRedis is particularily useful for HTTP session stores, and for caches.\nWhen setting a key, you can set an \"expiration\" (in seconds, milliseconds,\nor Unix timestamps):\n\n```\n127.0.0.1:1337\u003e EXPIRE theanswer 10\n(integer) 1\n127.0.0.1:1337\u003e TTL theanswer\n(integer) 6\n127.0.0.1:1337\u003e GET theanswer\n\"42\"\n127.0.0.1:1337\u003e TTL theanswer\n(integer) -2\n127.0.0.1:1337\u003e GET theanswer\n(nil)\n```\n\nWe are using \"strings\" here. In Redis \"strings\" are actually \"Data\" objects,\ni.e. binary arrays of bytes (this is even true for bytes!).\nFor example in a web application, you could use the \"session-id\" you generate,\nserialize your session into a Data object, and then store it like\n`SET session-id \u003csession\u003e TTL 600`.\n  \n### Key Generation\n\nBut how do we generate keys (e.g. session-ids) in a distributed setting?\nAs usual there are many ways to do this.\nFor example you could use a Redis integer key which provides atomic increment\nand decrement operations:\n\n```\n127.0.0.1:1337\u003e SET idsequence 0\nOK\n127.0.0.1:1337\u003e INCR idsequence\n(integer) 1\n127.0.0.1:1337\u003e INCR idsequence\n(integer) 2\n```\n\nOr if you generate keys on the client side, you can validate that they are\nunique using [SETNX](https://redis.io/commands/setnx). For example:\n\n```\n127.0.0.1:1337\u003e SETNX mykey 10\n(integer) 1\n```\n\nAnd another client will get\n\n```\n127.0.0.1:1337\u003e SETNX mykey 10\n(integer) 0\n```\n\n### Simple Lists\n\nRedis cannot only store string (read: Data) values, it can also store\nlists, sets and hashes (dictionaries).\nAs well as some other datatypes:\n[Data Types Intro](https://redis.io/topics/data-types-intro).\n\n```\n127.0.0.1:1337\u003e RPUSH chatchannel \"Hi guys!\"\n(integer) 1\n127.0.0.1:1337\u003e RPUSH chatchannel \"How is it going?\"\n(integer) 2\n127.0.0.1:1337\u003e LLEN chatchannel\n(integer) 2\n127.0.0.1:1337\u003e LRANGE chatchannel 0 -1\n1) \"Hi guys!\"\n2) \"How is it going?\"\n127.0.0.1:1337\u003e RPOP chatchannel\n\"How is it going?\"\n127.0.0.1:1337\u003e RPOP chatchannel\n\"Hi guys!\"\n127.0.0.1:1337\u003e RPOP chatchannel\n(nil)\n```\n\n### Monitoring\n\nAssume you want to debug what's going on on your Redis server.\nYou can do this by connecting w/ a fresh client and put that into\n\"monitoring\" mode. The Redis server will echo all commands it receives\nto that monitor:\n\n```\n$ redis-cli -p 1337\n127.0.0.1:1337\u003e MONITOR\nOK\n```\n\nSome other client:\n\n```\n127.0.0.1:1337\u003e hmset user:1000 username antirez birthyear 1976 verified 1\nOK\n127.0.0.1:1337\u003e hmget user:1000 username verified\n1) \"antirez\"\n2) \"1\"\n```\n\nThe monitor will print:\n\n```\n1523545069.071390 [0 127.0.0.1:60904] \"hmset\" \"user:1000\" \"username\" \"antirez\" \"birthyear\" \"1976\" \"verified\" \"1\"\n1523545087.016070 [0 127.0.0.1:60904] \"hmget\" \"user:1000\" \"username\" \"verified\"\n```\n\n### Publish/Subscribe\n\nRedis includes a simple publish/subscribe server.\nAny numbers of clients can subscribe to any numbers of channels.\nOther clients can then push \"messages\" to a channel, and all\nsubscribed clients will receive them.\n\nOne client:\n```\n127.0.0.1:1337\u003e PSUBSCRIBE thermostats*\nReading messages... (press Ctrl-C to quit)\n1) psubscribe\n2) \"thermostats*\"\n3) (integer) 1\n```\n\nAnother client (the reply contains the number of consumers):\n\n```\n127.0.0.1:1337\u003e PUBLISH thermostats:kitchen \"temperature set to 42℃\"\n(integer) 1\n```\n\nThe subscribed client will get:\n```\n1) message\n2) \"thermostats:kitchen\"\n3) \"temperatur set to 4242℃\"\n```\n\n\u003e Note: PubSub is separate to the key-value store. You cannot watch keys using\n\u003e that! (there are blocking list operations for producer/consumer scenarios,\n\u003e but those are not yet supported by Redi/S)\n\n\n### Benchmarking\n\nRedis tools also include a tool called `redis-benchmark` which can be,\nsimilar to `apache-bench` or `wrk` be used to measure the server performance.\n\nFor example, to exercise the server with half a million SET, GET, RPUSH and INCR\nrequests each:\n\n```\n$ redis-benchmark -p 1337 -t SET,GET,RPUSH,INCR -n 500000 -q\nSET: 43192.81 requests per second\nGET: 46253.47 requests per second\nINCR: 38952.95 requests per second\nRPUSH: 39305.09 requests per second\n```\n\n\n## Who\n\nBrought to you by\n[ZeeZide](http://zeezide.de).\nWe like\n[feedback](https://twitter.com/ar_institute),\nGitHub stars,\ncool [contract work](http://zeezide.com/en/services/services.html),\npresumably any form of praise you can think of.\n\nThere is a `#swift-nio` channel on the\n[swift-server Slack](https://t.co/W1vfsb9JAB).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnozeio%2Fredi-s","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnozeio%2Fredi-s","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnozeio%2Fredi-s/lists"}