{"id":20653166,"date":"2022-01-10T08:08:30","date_gmt":"2022-01-10T16:08:30","guid":{"rendered":"https:\/\/thenewstack.io\/?p=20653166"},"modified":"2022-01-10T08:08:30","modified_gmt":"2022-01-10T16:08:30","slug":"redis-pub-sub-vs-apache-kafka","status":"publish","type":"post","link":"https:\/\/thenewstack.io\/redis-pub-sub-vs-apache-kafka\/","title":{"rendered":"Redis Pub\/Sub vs. Apache Kafka"},"content":{"rendered":"<p>Redis is the &ldquo;Swiss Army knife&rdquo; of <a href=\"https:\/\/www.instaclustr.com\/its-an-in-memory-key-value-store-its-a-database-its-redis\/\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">in-memory databases with many data types<\/a>, and <a href=\"https:\/\/www.instaclustr.com\/redis-java-clients-and-client-side-caching\/\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">it&rsquo;s often used for caching<\/a>, but it does even more. It can also function as a loosely coupled distributed message broker, so in this article, we&rsquo;ll have a look at the original Redis messaging approach, Redis Pub\/Sub, explore some use cases and compare it with Apache Kafka.<\/p>\n<h2>1. Redis Pub\/Sub<\/h2>\n<div id=\"attachment_20657243\" style=\"width: 650px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-20657243\" class=\"wp-image-20657243 size-large\" src=\"https:\/\/cdn.thenewstack.io\/media\/2022\/01\/aa8503bf-image1-1024x687.jpeg\" alt=\"\" width=\"640\" height=\"429\" \/><p id=\"caption-attachment-20657243\" class=\"wp-caption-text\">A Beatles-inspired submarine cocktail. <a href=\"https:\/\/www.shutterstock.com\/image-photo\/fresh-lemon-yellow-submarine-blue-water-32171176\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">Image<\/a> used under license from Shutterstock.com. Contributor: <a href=\"https:\/\/www.shutterstock.com\/g\/valery_evlakhov\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">Evlakhov Valerii<\/a><\/p><\/div>\n<p>The theme of &ldquo;pub&rdquo; pops up frequently in my articles. In a previous article, I wrote about a conversation in an outback pub, &ldquo;<a href=\"https:\/\/www.instaclustr.com\/apache-zookeeper-meets-the-dining-philosophers\/\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">Apache ZooKeeper Meets the Dining Philosophers,<\/a>&rdquo; and in this article, we are investigating Redis Pub\/Sub. This sounds like some sort of Beatles-inspired exotic yellow submarine cocktail, but Pub\/Sub is actually short for publish\/subscribe, the well-known pattern for loosely-coupled distributed messaging systems.<\/p>\n<a href=\"https:\/\/au.linkedin.com\/in\/paul-brebner-0a547b4\" class=\"clearfix infoBlock \" style=\"float: right;margin: 8px -100px 5px 15px;\" target=\"_blank\">\n\t\t\t\t<div class=\"infoBlockImageBlock\" style=\"\">\n\t\t\t\t\t<img decoding=\"async\" class=\"infoBlockImage\" src=\"https:\/\/cdn.thenewstack.io\/media\/2022\/01\/8c9c1ad7-paul-brebner-e1641584072260.jpg\" style=\"border-radius: 50%\">\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"infoBlockTextBlock\">\n\t\t\t\t\t<div class=\"infoBlockTitle\" style=\"\">Paul Brebner<\/div>\n\t\t\t\t\t<div class=\"infoBlockText\"><br \/>\nPaul is the technology evangelist at Instaclustr. He\u2019s been learning new scalable big data technologies, solving real problems and building applications, and blogging about Apache Cassandra, Spark, Zeppelin, and Kafka. Paul has extensive R&D and industry experience in distributed systems, technology innovation, software architecture and engineering, software performance and scalability, grid and cloud computing, and data analytics and machine learning.<\/div>\n\t\t\t\t<\/div>\n\t\t\t<\/a>\n<p><a href=\"https:\/\/redis.io\/topics\/pubsub\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">Redis Pub\/Sub<\/a> is the oldest style of messaging pattern supported by Redis and uses a data type called a &ldquo;channel,&rdquo; which supports typical pub\/sub operations, such as publish and subscribe. It&rsquo;s considered loosely coupled because publishers and subscribers don&rsquo;t know about each other. Publishers publish messages to a channel, or multiple channels, and subscribers subscribe to one or more channels.<\/p>\n<p>A channel can have zero or more subscribers, and the messages are delivered to all the current connected subscribers. Redis Pub\/Sub is therefore flexible and supports multiple topologies including fan-in (multiple producers, single subscriber), fan-out (single producer, multiple subscribers), and 1-1 (one producer, one consumer).<\/p>\n<p>So far this sounds like a fairly typical pub\/sub system, however, one feature is important to highlight: &ldquo;connected&rdquo; delivery semantics.<\/p>\n<h2>2. Connected Delivery Semantics<\/h2>\n<p>Connected delivery functions like radio. Radio stations are constantly broadcasting on different frequencies (channels), but listeners can only hear the broadcast while their receiver is plugged in, turned on, and they are tuned in to a station. (&ldquo;Stay tuned&rdquo; could be the motto for Redis Pub\/Sub).<\/p>\n<div id=\"attachment_20657256\" style=\"width: 650px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-20657256\" class=\"wp-image-20657256 size-large\" src=\"https:\/\/cdn.thenewstack.io\/media\/2022\/01\/9523da82-image3-788x1024.jpeg\" alt=\"\" width=\"640\" height=\"832\" \/><p id=\"caption-attachment-20657256\" class=\"wp-caption-text\">Redis Pub\/Sub &mdash; to listen, plugin, turn on and tune in. <a href=\"https:\/\/www.shutterstock.com\/image-photo\/tuning-92662957\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">Image<\/a> used under license from Shutterstock.com. Contributor: <a href=\"https:\/\/www.shutterstock.com\/g\/everett\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">Everett Collection<\/a><\/p><\/div>\n<p>Connected delivery means that:<\/p>\n<ol>\n<li aria-level=\"1\">Only connected subscribers receive messages.<\/li>\n<li aria-level=\"1\">Every connected subscriber receives each message.<\/li>\n<li aria-level=\"1\">Once the message is delivered to all current subscribers, it is deleted from the channel (there&rsquo;s no &ldquo;memory&rdquo; in the system).<\/li>\n<\/ol>\n<p>This implies that:<\/p>\n<ol>\n<li aria-level=\"1\">If a subscriber unsubscribes (disconnects) and later subscribes to a channel again:\n<ol>\n<li aria-level=\"2\">It will not receive any of the intervening messages that it missed while disconnected, and<\/li>\n<li aria-level=\"2\">It doesn&rsquo;t know if it&rsquo;s missed any messages.<\/li>\n<\/ol>\n<\/li>\n<li aria-level=\"1\">If there are no current subscribers to the channel,&nbsp; the message will simply be discarded and not delivered to any subscribers.<\/li>\n<li aria-level=\"1\">The delivery semantics are, therefore, &ldquo;at-most-once&rdquo; per subscriber.<\/li>\n<li aria-level=\"1\">Because the message must be delivered to all current subscribers before being deleted:\n<ol>\n<li aria-level=\"2\">This will take longer with more subscribers.<\/li>\n<li aria-level=\"2\">This is unlike a radio broadcast, which delivers content currently at the speed of light to every receiver in range.<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p>Note that &ldquo;disconnection&rdquo; is intentional by design, but can also be due to network or client failures, so may be unexpected, and this will also result in potential message loss.<\/p>\n<p>From reading the Redis Pub\/Sub <a href=\"https:\/\/redis.com\/ebook\/part-2-core-concepts\/chapter-3-commands-in-redis\/3-6-publishsubscribe\/\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">documentation,<\/a> and <a href=\"https:\/\/making.pusher.com\/redis-pubsub-under-the-hood\/\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">other articles<\/a>, it appears that Redis uses push notification to ensure messages are delivered to all current subscribers, which has potential performance penalties for large numbers of subscribers.<\/p>\n<h2>3. Use Cases for Redis Pub\/Sub<\/h2>\n<div id=\"attachment_20657257\" style=\"width: 650px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-20657257\" class=\"wp-image-20657257 size-large\" src=\"https:\/\/cdn.thenewstack.io\/media\/2022\/01\/e66c974d-image2-1024x683.jpeg\" alt=\"\" width=\"640\" height=\"427\" \/><p id=\"caption-attachment-20657257\" class=\"wp-caption-text\">Redis Pub\/Sub channels can have multiple subscribers, but too many may have a performance impact (unlike real radio which works perfectly for unlimited receivers). <a href=\"https:\/\/www.shutterstock.com\/image-photo\/vintage-radios-34992457\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">Image<\/a> used under license from Shutterstock.com. Contributor:<a href=\"https:\/\/www.shutterstock.com\/g\/robertochamorro\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\"> jimeone<\/a><\/p><\/div>\n<p>What are appropriate use cases for the Redis Pub\/Sub &ldquo;connected&rdquo; delivery semantics?<\/p>\n<ol>\n<li aria-level=\"1\">Real-time, low-latency, urgent messages: If messages are short-lived and age rapidly, so, therefore, are only relevant to subscribers for a short time window (basically &ldquo;immediately&rdquo;).<\/li>\n<li aria-level=\"1\">Unreliable delivery\/lossy messaging: If it doesn&rsquo;t matter if some messages are simply discarded (redundant messages of low importance rather than uniquely critical &ldquo;business&rdquo; messages) due to unreliable delivery. Failures in the network and subscribers, or <a href=\"https:\/\/support.huaweicloud.com\/intl\/en-us\/ae-ad-1-usermanual-dcs\/dcs-faq-0730011.html\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">failover from master to replicas<\/a>, may all result in discarded messages.<\/li>\n<li aria-level=\"1\">A requirement for at-most-once delivery per subscriber (subscribers are not capable of detecting duplicate messages and target systems are not idempotent.)<\/li>\n<li aria-level=\"1\">If subscribers have short-lived, evolving or dynamic interest in channels, and only want to receive messages from specific channels for finite periods of time. For instance, mobile IoT devices may only be intermittently connected, and only interested and able to respond to current messages at their location.<\/li>\n<li aria-level=\"1\">If subscribers &mdash; and channels and publishers too &mdash; are themselves potentially short-lived.<\/li>\n<li aria-level=\"1\">One or more subscribers per channel, but&#8230;<\/li>\n<li aria-level=\"1\">There are only a small number of subscribers and patterns per channel.<\/li>\n<\/ol>\n\n<div\n\tclass=\"tns-sponsor-note \"\n\t>\n    <div class=\"sponsor-note-content-wrapper\">\n\t\t<div class=\"sponsor-note-profile\" data-url=\"https:\/\/www.instaclustr.com\/?utm_content=sponsor+module\" data-sponsor=\"instaclustr\">\n\t\t\t<div class=\"row\">\n\t\t\t\t<div class=\"col col-40 sponsor-note-logo\">\n\t\t            <a href=\"https:\/\/www.instaclustr.com\/?utm_content=sponsor+module\" class=\"sponsor-note-logo-link\" target=\"_blank\">\n\t\t\t\t\t\t<span><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/cdn.thenewstack.io\/media\/2021\/11\/73cd1ea5-instaclustr_netapp_logo.svg\" width=\"125\" height=\"30\" alt=\"\"><\/span>\n\t\t            <\/a>\n\t\t\t\t<\/div>\n\t\t\t<\/div>\n\t\t\t<div class=\"row\">\n\t\t\t\t<div class=\"col sponsor-note-content\">\n\t\t\t\t\tInstaclustr delivers reliability at scale through an integrated data platform of open source technologies such as Apache Cassandra&reg;, Apache Kafka&reg;, Apache SparkTM, ElasticsearchTM, RedisTM, Apache ZooKeeperTM, and PostgreSQL&reg;.\n\t\t\t\t<\/div>\n\t\t\t<\/div>\n\t\t\t<div class=\"row\">\n\t\t\t\t<div class=\"col sponsor-note-cta\">\n\t\t\t\t\tLearn More<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"23.012\" height=\"17.268\" viewBox=\"0 0 23.012 17.268\">\n  <path id=\"Path_340\" data-name=\"Path 340\" d=\"M14.36,0,12.816,1.508l6.067,6.067H0V9.729H18.884l-6.031,6.032L14.4,17.268l8.616-8.616Z\" transform=\"translate(0 0)\"\/>\n<\/svg>\n\t\t\t\t<\/div>\n\t\t\t<\/div>\n        <\/div>\n\n                <div class=\"sponsor-note-rss\" data-sponsor=\"instaclustr\">\n\t\t\t<div class=\"sponsor-note-rss-heading\">\n\t\t\t\tThe latest from Instaclustr\t\t\t<\/div>\n\t\t\t<div\n\t\t\t\tclass=\"sponsor-note-rss-items sponsor-note-rss-items-instaclustr\"\n\t\t\t\tdata-sponsor=\"instaclustr\"\n\t\t\t><\/div>\n\t\t\t<script>\n\t\t\t\t$(document).ready(function() {\n\t\t\t\t\t$.ajax({\n\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\turl: '\/no-cache\/sponsors-rss-block\/',\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t'Cache-Control': 'no-cache, no-store, must-revalidate',\n\t\t\t\t\t\t\t'Pragma': 'no-cache',\n\t\t\t\t\t\t\t'Expires': '0'\n\t\t\t\t\t\t},\n\t\t\t\t\t\tdata : {\n\t\t\t\t\t\t\tsponsorSlug : 'instaclustr',\n\t\t\t\t\t\t\tnumItems : 3\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsuccess : function(data) {\n\t\t\t\t\t\t\tif (data == \"\") {\n\t\t\t\t\t\t\t\t$('.sponsor-note-rss').hide();\n\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (data.startsWith('ERROR')) {\n\t\t\t\t\t\t\t\tconsole.log(data)\n\t\t\t\t\t\t\t\t$('.sponsor-note-rss').hide();\n\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t$('.sponsor-note-rss-items-instaclustr').html(data);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t});\n        <\/script>\n        <\/div>\n            <\/div>\n\n\n\t<script>\n\t\t$(document).ready(function () {\n\t\t\tvar publication = 'thenewstack'\n\n\t\t\t\/\/ 1) Enter key on email input triggers submit click\n\t\t\t$(document).on('keydown', '.tns-sponsor-note .sponsor-note-lead-form-input', function (event) {\n\t\t\t\tif (event.key === 'Enter') {\n\t\t\t\t\tevent.preventDefault()\n\t\t\t\t\t$(this).closest('.tns-sponsor-note').find('.sponsor-note-lead-form-submit').trigger('click')\n\t\t\t\t}\n\t\t\t})\n\n\t\t\t\/\/ 2) If already logged-in, pre-populate the email field\n\t\t\tvar userCookieJSONPrefill = window.tns.getCookie('tns-user')\n\t\t\tif (userCookieJSONPrefill) {\n\t\t\t\tvar currentUserPrefill = JSON.parse(userCookieJSONPrefill)\n\t\t\t\tif (currentUserPrefill && currentUserPrefill.email) {\n\t\t\t\t\t$('.tns-sponsor-note .sponsor-note-lead-form-input').val(currentUserPrefill.email)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction getStatusBox($root) {\n\t\t\t\treturn $root.find('.sponsor-note-lead-form-status')\n\t\t\t}\n\n\t\t\tfunction showSuccessMessage($root) {\n\t\t\t\tvar $wrapper = $root.find('.sponsor-note-lead-form-input-wrapper')\n\t\t\t\tvar $status = getStatusBox($root)\n\t\t\t\tvar wrapperHeight = $wrapper.outerHeight()\n\t\t\t\t$status.css({ height: wrapperHeight + 'px' })\n\t\t\t\t$wrapper.stop().transition({ duration: 250, opacity: 0 }, function () {\n\t\t\t\t\t$wrapper.css({ display: 'none' })\n\t\t\t\t\t$status.text(\"Thank you! We'll share your info with this sponsor.\")\n\t\t\t\t\t$status.css({ display: 'block', opacity: 0 })\n\t\t\t\t\t$status.stop().transition({ delay: 50, duration: 250, opacity: 1 })\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tfunction showErrorMessageThenRestore($root) {\n\t\t\t\tvar $wrapper = $root.find('.sponsor-note-lead-form-input-wrapper')\n\t\t\t\tvar $status = getStatusBox($root)\n\t\t\t\tvar wrapperHeight = $wrapper.outerHeight()\n\t\t\t\t$status.css({ height: wrapperHeight + 'px' })\n\t\t\t\t$wrapper.stop().transition({ duration: 250, opacity: 0 }, function () {\n\t\t\t\t\t$wrapper.css({ display: 'none' })\n\t\t\t\t\t$status.text('Something went wrong on our end, please try again')\n\t\t\t\t\t$status.css({ display: 'block', opacity: 0 })\n\t\t\t\t\t$status.stop().transition({ delay: 50, duration: 250, opacity: 1 }, function () {\n\t\t\t\t\t\tsetTimeout(function () {\n\t\t\t\t\t\t\t$status.stop().transition({ duration: 250, opacity: 0 }, function () {\n\t\t\t\t\t\t\t\t$status.css({ display: 'none' })\n\t\t\t\t\t\t\t\t$wrapper.css({ display: 'block', opacity: 0 })\n\t\t\t\t\t\t\t\t$wrapper.stop().transition({ duration: 250, opacity: 1 })\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t}, 5000)\n\t\t\t\t\t})\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t$(document).on('click', '.tns-sponsor-note .sponsor-note-lead-form-submit', function (event) {\n\t\t\t\tevent.preventDefault()\n\n\t\t\t\tvar $sponsorNoteRoot = $(this).closest('.tns-sponsor-note')\n\t\t\t\tif (!$sponsorNoteRoot.length) console.log('[IMGJS] No Sponsor Note found')\n\n\t\t\t\tvar sponsorSlug = ($sponsorNoteRoot.find('.sponsor-note-profile').data('sponsor') || '').toString().trim()\n\t\t\t\tvar categories = $sponsorNoteRoot.data('categories')\n\t\t\t\tif (!sponsorSlug || !publication)  console.log('[IMGJS] Missing publication or sponsor')\n\n\t\t\t\tvar emailPrefillValue = $.trim($sponsorNoteRoot.find('.sponsor-note-lead-form-input').val() || '')\n\n\t\t\t\tvar userCookieJSON = window.tns.getCookie('tns-user')\n\t\t\t\tvar currentUser = userCookieJSON ? JSON.parse(userCookieJSON) : null\n\n\t\t\t\tif (currentUser && currentUser.author_id && currentUser.email) {\n\t\t\t\t\tvar reactionPayload = {\n\t\t\t\t\t\tauthor_id: currentUser.author_id,\n\t\t\t\t\t\temail: currentUser.email,\n\t\t\t\t\t\treaction: 'sales-lead',\n\t\t\t\t\t\tobject_type: 'sponsor',\n\t\t\t\t\t\tobject_id: 'sponsor_' + sponsorSlug,\n\t\t\t\t\t\tpublication: publication\n\t\t\t\t\t}\n\n\t\t\t\t\timgjs.reactions.postReaction(reactionPayload).then(function (response) {\n\t\t\t\t\t\tif (response && response.ok && response.status !== 409) {\n\t\t\t\t\t\t\tvar reactionPayloadDl = {\n\t\t\t\t\t\t\t\tevent: 'reaction',\n\t\t\t\t\t\t\t\treaction: 'sales-lead',\n\t\t\t\t\t\t\t\tobject_type: 'sponsor',\n\t\t\t\t\t\t\t\tobject_id: 'sponsor_' + sponsorSlug\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (categories) {\n\t\t\t\t\t\t\t\treactionPayloadDl.categories = categories\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\twindow.dataLayer.push(reactionPayloadDl)\n\n\t\t\t\t\t\t\tshowSuccessMessage($sponsorNoteRoot)\n\t\t\t\t\t\t} else if (response && response.status === 409) {\n\t\t\t\t\t\t\tshowSuccessMessage($sponsorNoteRoot)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tshowErrorMessageThenRestore($sponsorNoteRoot)\n\t\t\t\t\t\t}\n\t\t\t\t\t}).catch(function () {\n\t\t\t\t\t\tshowErrorMessageThenRestore($sponsorNoteRoot)\n\t\t\t\t\t})\n\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tvar previousOnCloseHandler = imgjs.subscribe.config.onClose\n\t\t\t\timgjs.subscribe.config.onClose = function (userFromPopover) {\n\t\t\t\t\timgjs.subscribe.config.onClose = previousOnCloseHandler\n\t\t\t\t\t\n\t\t\t\t\tvar finalUserObject = userFromPopover\n\t\t\t\t\t\n\t\t\t\t\tif (!finalUserObject) {\n\t\t\t\t\t\tvar userAfterLoginJSON = window.tns.getCookie('tns-user')\n\t\t\t\t\t\tfinalUserObject = userAfterLoginJSON ? JSON.parse(userAfterLoginJSON) : null\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (finalUserObject && finalUserObject.author_id && finalUserObject.email) {\n\t\t\t\t\t\t\/\/ Set auth cookies and update masthead login button (consistent with other onClose handlers)\n\t\t\t\t\t\twindow.tns.setCookie('tns-user-id', finalUserObject.author_id, 8400)\n\t\t\t\t\t\twindow.tns.setCookie('tns-user', JSON.stringify(finalUserObject), 8400)\n\t\t\t\t\t\t$('.masthead-login-button').text('')\n\t\t\t\t\t\tvar reactionPayloadAfterLogin = {\n\t\t\t\t\t\t\tauthor_id: finalUserObject.author_id,\n\t\t\t\t\t\t\temail: finalUserObject.email,\n\t\t\t\t\t\t\treaction: 'sales-lead',\n\t\t\t\t\t\t\tobject_type: 'sponsor',\n\t\t\t\t\t\t\tobject_id: 'sponsor_' + sponsorSlug,\n\t\t\t\t\t\t\tpublication: publication\n\t\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t\timgjs.reactions.postReaction(reactionPayloadAfterLogin).then(function (response) {\n\t\t\t\t\t\t\tif (response && response.ok && response.status !== 409) {\n\t\t\t\t\t\t\t\tvar reactionPayloadAfterLoginDl = {\n\t\t\t\t\t\t\t\t\tevent: 'reaction',\n\t\t\t\t\t\t\t\t\treaction: 'sales-lead',\n\t\t\t\t\t\t\t\t\tobject_type: 'sponsor',\n\t\t\t\t\t\t\t\t\tobject_id: 'sponsor_' + sponsorSlug,\n\t\t\t\t\t\t\t\t\tpublication: publication\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (categories) {\n\t\t\t\t\t\t\t\t\treactionPayloadAfterLoginDl.categories = categories\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\twindow.dataLayer.push(reactionPayloadAfterLoginDl)\n\t\t\t\t\t\t\t\tshowSuccessMessage($sponsorNoteRoot)\n\t\t\t\t\t\t\t} else if (response && response.status === 409) {\n\t\t\t\t\t\t\t\tshowSuccessMessage($sponsorNoteRoot)\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tshowErrorMessageThenRestore($sponsorNoteRoot)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}).catch(function () {\n\t\t\t\t\t\t\tshowErrorMessageThenRestore($sponsorNoteRoot)\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\n\t\t\t\t\t\/\/\/ Set the channel data for the user_registration GA4 event\n\t\t\t\t\twindow.imgjs.subscribe.channel = 'reaction'\n\t\t\t\t\twindow.imgjs.subscribe.channel_id = 'leadgen'\n\n\t\t\t\t\t\/\/\/ Determine if it's a new subscription by testing\n\t\t\t\t\t\/\/\/ if the createdAt date is today's date\n\t\t\t\t\tif (window.imgjs.subscribe.isNewSubscription(userFromPopover.createdAt)) {\n\t\t\t\t\t    var userRegistrationPayload = {\n\t\t\t                'event' : 'user_registration',\n\t\t\t                'url' : window.location.href,\n\t\t\t                'channel': window.imgjs.subscribe.channel,\n\t\t\t                'channel_id': window.imgjs.subscribe.channel_id\n\t\t\t            }\n\n\t\t\t\t\t\tif (categories) {\n\t\t\t\t\t\t\tuserRegistrationPayload.categories = categories\n\t\t\t\t\t\t}\n\n\t\t\t\t\t    window.dataLayer.push(userRegistrationPayload)\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif ($.isFunction(previousOnCloseHandler)) previousOnCloseHandler(userFromPopover)\n\t\t\t\t}\n\n\t\t\t\timgjs.subscribe.config.copy.email_slide.cta.login = 'Please login or create an account to continue ...'\n\t\t\t\timgjs.subscribe.config.images.email_slide.key_image = ''\n\t\t\t\timgjs.subscribe.config.copy.confirm_slide.whats_next.login = \"Our sponsor will be in touch with more information.\"\n\n\t\t\t\tvar subscriptions = {\n\t\t\t\t\tmc : [\n\t\t\t\t\t\t'6166149401' \/\/\/ TNS Daily\n\t\t\t\t\t],\n\t\t\t\t\ths : []\n\t\t\t\t}\n\n\t\t\t\tconst hostname = window.location.hostname\n\n\t\t\t\tswitch (true) {\n\t\t\t\t\tcase hostname.includes(\"thenewstack.io\"):\n\t\t\t\t\t\tsubscriptions.hs.push(\"688810478\") \/\/\/ TNS Daily (PROD)\n\t\t\t\t\t\tbreak\n\n\t\t\t\t\tcase hostname.includes(\"thenewstack.dev\"):\n\t\t\t\t\t\tsubscriptions.hs.push(\"860037297\") \/\/\/ TNS Daily (SANDBOX)\n\t\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\t\/\/ Ensure the popover pre-populates the email but does NOT auto-click for lead form\n\t\t\t\timgjs.subscribe.open(emailPrefillValue || null, subscriptions, 'login', null, true, false)\n\t\t\t})\n\t\t})\n\t<\/script>\n<\/div>\n\n\n<h2>4. Redis Pub\/Sub Compared with Apache Kafka<\/h2>\n<p>Finally, I wondered if Apache Kafka can do something similar to Redis Pub\/Sub? Can Kafka do:<\/p>\n<h3 style=\"padding-left: 40px;\"><strong>1. Replicated delivery to multiple subscribers?<\/strong><\/h3>\n<p>Yes. This corresponds to multiple consumer groups in Kafka. A message sent to a Kafka topic with multiple consumer groups is received by one consumer in each group. However, to ensure that only a single consumer per consumer group gets each message, in Kafka you would have a sole subscriber per consumer group.<\/p>\n<h3 style=\"padding-left: 40px;\"><strong>2. &#8216;No key&#8217; message delivery?<\/strong><\/h3>\n<p>Redis Pub\/Sub messages don&rsquo;t have a key, just a value, although in Redis the channel is really the key.<\/p>\n<p>Yes, as keys are optional in Kafka. If there&rsquo;s no key, then Kafka uses a round-robin load-balancing algorithm to distribute the messages sent to a topic among the available consumers in each group. If there&rsquo;s only one consumer, then that consumer gets all the messages.<\/p>\n<h3 style=\"padding-left: 40px;\"><strong>3. Unreliable message delivery?&nbsp;<\/strong><\/h3>\n<p>Yes, Kafka can do this as well, as Kafka consumers can choose what offset, or alternately time, to read from, enabling tricks like replaying the same messages, reliable disconnected delivery from the last read message and skipping messages etc. Kafka consumers poll for messages, so each time they poll, they can choose to read from the next (unread) offset, or alternatively, they can skip the unread messages and start reading from the end offset (using <a href=\"https:\/\/kafka.apache.org\/22\/javadoc\/org\/apache\/kafka\/clients\/consumer\/KafkaConsumer.html#seekToEnd-java.util.Collection-\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">seekToEnd()<\/a>), and only read new messages. This is certainly not the normal model of operation for Kafka, but it is logically possible and fits several use cases and operational requirements, such as if consumers are getting behind, they can catch up by skipping messages, etc.<\/p>\n<h3 style=\"padding-left: 40px;\"><strong>4. Low-latency &#8216;instant&#8217; message delivery?<\/strong><\/h3>\n<p>Redis Pub\/Sub is designed for speed (low latency), but only with low numbers of subscribers. Subscribers don&rsquo;t poll and while subscribed\/connected are able to receive push notifications very quickly from the Redis broker &mdash; in the low milliseconds, <a href=\"https:\/\/gist.github.com\/hmartiro\/85b89858d2c12ae1a0f9\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">even less than 1 millisecond as confirmed by this benchmark<\/a>.<\/p>\n<p>Also note that some articles report that Redis Pub\/Sub performance is sensitive to message size; it works well with small messages, but not large ones.<\/p>\n<p>Average Kafka latency is typically in the low 10s of milliseconds. (The average producer latency was 15 to 30 milliseconds reported in our <a href=\"https:\/\/www.instaclustr.com\/the-power-of-kafka-partitions-how-to-get-the-most-out-of-your-kafka-cluster\/\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">partition benchmarking article<\/a>).<\/p>\n<p>Kafka also <a href=\"https:\/\/dzone.com\/articles\/processing-large-messages-with-apache-kafka\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">wasn&rsquo;t designed for large messages<\/a>, but it can work with reasonably large messages, even up to 1GB, particularly if compression is enabled and potentially in conjunction with <a href=\"https:\/\/cwiki.apache.org\/confluence\/display\/KAFKA\/KIP-405%3A+Kafka+Tiered+Storage\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">Kafka tiered storage<\/a>.<\/p>\n<h3 style=\"padding-left: 40px;\"><strong>5. Throughput?<\/strong><\/h3>\n<p>To maximize Redis throughput, you need to pipeline the producer publish operation, but this will push out the latency, so you can&rsquo;t have both low latency and high throughput with Redis Pub\/Sub.<\/p>\n<p>Redis is mostly single-threaded, so the only way to improve broker concurrency is by increasing the number of nodes in a cluster.<\/p>\n<p>On the other hand, Kafka consumers rely on polling, and potentially batching of messages, so the latency will be potentially slightly higher, typically 10s of milliseconds. However, scalability is better due to Kafka consumer groups and topic partitions, which enable very high consumer concurrency backed by broker concurrency (multiple nodes and partitions).<\/p>\n<h3 style=\"padding-left: 40px;\"><strong>6. Durability and Reliability?<\/strong><\/h3>\n<p>And just a reminder that Redis Pub\/Sub isn&rsquo;t durable (the channels are in-memory only), but Kafka is highly durable (it&rsquo;s disk-based, and has configurable replication to multiple different nodes).<\/p>\n<p>Kafka also has automatic failover for consumers in groups &mdash; if consumers fail, others take over (but watch out for <a href=\"https:\/\/www.instaclustr.com\/apache-kafka-kongo-6-3-production-kafka-application-scalng-on-instaclustr\/\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">rebalancing storms<\/a>). And <a href=\"https:\/\/www.instaclustr.com\/apache-kafka-connect-architecture-overview\/\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">Kafka Connect<\/a> enables higher reliability by automatically restarting connector tasks <a href=\"https:\/\/www.instaclustr.com\/data-processing-pipeline-part-2\/\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">for some failure modes<\/a>. Given that Redis Pub\/Sub doesn&rsquo;t have the concept of subscriber groups, you are on your own here and would need to handle this differently, perhaps running Redis subscriber clients in <a href=\"https:\/\/www.instaclustr.com\/anomalia-machina-7-application-deployment-kubernetes\/\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">Kubernetes pods<\/a> with automatic restarts and scaling, etc.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Redis is the &ldquo;Swiss Army knife&rdquo; of in-memory databases with many data types, and it&rsquo;s often used for caching, but<\/p>\n","protected":false},"author":1799,"featured_media":20657258,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[12005,10061,83],"tags":[6483,12163,3319,12344],"coauthors":[12008],"class_list":["post-20653166","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-data","category-networking","category-technology","tag-contributed","tag-sponsor-instaclustr","tag-sponsored","tag-sponsored-post-contributed"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.6 (Yoast SEO v27.6) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Redis Pub\/Sub vs. Apache Kafka - The New Stack<\/title>\n<meta name=\"description\" content=\"Redis Pub\/Sub sounds like a fairly typical pub\/sub system, but it can do more. Let&#039;s compare it to Apache Kafka.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/thenewstack.io\/redis-pub-sub-vs-apache-kafka\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Redis Pub\/Sub vs. Apache Kafka\" \/>\n<meta property=\"og:description\" content=\"Redis Pub\/Sub sounds like a fairly typical pub\/sub system, but it can do more. Let&#039;s compare it to Apache Kafka.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/thenewstack.io\/redis-pub-sub-vs-apache-kafka\/\" \/>\n<meta property=\"og:site_name\" content=\"The New Stack\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/thenewstack\" \/>\n<meta property=\"article:published_time\" content=\"2022-01-10T16:08:30+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/cdn.thenewstack.io\/media\/2022\/01\/e6884bbf-image4.jpeg\" \/>\n\t<meta property=\"og:image:width\" content=\"1999\" \/>\n\t<meta property=\"og:image:height\" content=\"1303\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Paul Brebner\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@thenewstack\" \/>\n<meta name=\"twitter:site\" content=\"@thenewstack\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Paul Brebner\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\\\/\\\/thenewstack.io\\\/redis-pub-sub-vs-apache-kafka\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/thenewstack.io\\\/redis-pub-sub-vs-apache-kafka\\\/\"},\"author\":{\"name\":\"Paul Brebner\",\"@id\":\"https:\\\/\\\/thenewstack.io\\\/#\\\/schema\\\/person\\\/fac61d9018ed7a2f2afe3245eacb13fb\"},\"headline\":\"Redis Pub\\\/Sub vs. Apache Kafka\",\"datePublished\":\"2022-01-10T16:08:30+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/thenewstack.io\\\/redis-pub-sub-vs-apache-kafka\\\/\"},\"wordCount\":1546,\"publisher\":{\"@id\":\"https:\\\/\\\/thenewstack.io\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/thenewstack.io\\\/redis-pub-sub-vs-apache-kafka\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/cdn.thenewstack.io\\\/media\\\/2022\\\/01\\\/e6884bbf-image4.jpeg\",\"keywords\":[\"Contributed\",\"instaclustr\",\"Sponsored\",\"post-contributed\"],\"articleSection\":[\"Data\",\"Networking\",\"Technology\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/thenewstack.io\\\/redis-pub-sub-vs-apache-kafka\\\/\",\"url\":\"https:\\\/\\\/thenewstack.io\\\/redis-pub-sub-vs-apache-kafka\\\/\",\"name\":\"Redis Pub\\\/Sub vs. Apache Kafka - The New Stack\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/thenewstack.io\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/thenewstack.io\\\/redis-pub-sub-vs-apache-kafka\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/thenewstack.io\\\/redis-pub-sub-vs-apache-kafka\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/cdn.thenewstack.io\\\/media\\\/2022\\\/01\\\/e6884bbf-image4.jpeg\",\"datePublished\":\"2022-01-10T16:08:30+00:00\",\"description\":\"Redis Pub\\\/Sub sounds like a fairly typical pub\\\/sub system, but it can do more. Let's compare it to Apache Kafka.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/thenewstack.io\\\/redis-pub-sub-vs-apache-kafka\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/thenewstack.io\\\/redis-pub-sub-vs-apache-kafka\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/thenewstack.io\\\/redis-pub-sub-vs-apache-kafka\\\/#primaryimage\",\"url\":\"https:\\\/\\\/cdn.thenewstack.io\\\/media\\\/2022\\\/01\\\/e6884bbf-image4.jpeg\",\"contentUrl\":\"https:\\\/\\\/cdn.thenewstack.io\\\/media\\\/2022\\\/01\\\/e6884bbf-image4.jpeg\",\"width\":1999,\"height\":1303},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/thenewstack.io\\\/redis-pub-sub-vs-apache-kafka\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/thenewstack.io\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Redis Pub\\\/Sub vs. Apache Kafka\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/thenewstack.io\\\/#website\",\"url\":\"https:\\\/\\\/thenewstack.io\\\/\",\"name\":\"The New Stack\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/thenewstack.io\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/thenewstack.io\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/thenewstack.io\\\/#organization\",\"name\":\"The New Stack\",\"url\":\"https:\\\/\\\/thenewstack.io\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/thenewstack.io\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/cdn.thenewstack.io\\\/media\\\/2021\\\/11\\\/a9fbec84-the-new-stack-logo-rgb-screen.png\",\"contentUrl\":\"https:\\\/\\\/cdn.thenewstack.io\\\/media\\\/2021\\\/11\\\/a9fbec84-the-new-stack-logo-rgb-screen.png\",\"width\":1032,\"height\":128,\"caption\":\"The New Stack\"},\"image\":{\"@id\":\"https:\\\/\\\/thenewstack.io\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/thenewstack\",\"https:\\\/\\\/x.com\\\/thenewstack\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/thenewstack.io\\\/#\\\/schema\\\/person\\\/fac61d9018ed7a2f2afe3245eacb13fb\",\"name\":\"Paul Brebner\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/ad516503a11cd5ca435acc9bb6523536?s=9615105800a0270a384212262298083881\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/ad516503a11cd5ca435acc9bb6523536?s=96\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/ad516503a11cd5ca435acc9bb6523536?s=96\",\"caption\":\"Paul Brebner\"},\"sameAs\":[\"https:\\\/\\\/www.linkedin.com\\\/in\\\/paul-brebner-0a547b4\\\/\"],\"url\":\"https:\\\/\\\/thenewstack.io\\\/author\\\/paul-brebner\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Redis Pub\/Sub vs. Apache Kafka - The New Stack","description":"Redis Pub\/Sub sounds like a fairly typical pub\/sub system, but it can do more. Let's compare it to Apache Kafka.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/thenewstack.io\/redis-pub-sub-vs-apache-kafka\/","og_locale":"en_US","og_type":"article","og_title":"Redis Pub\/Sub vs. Apache Kafka","og_description":"Redis Pub\/Sub sounds like a fairly typical pub\/sub system, but it can do more. Let's compare it to Apache Kafka.","og_url":"https:\/\/thenewstack.io\/redis-pub-sub-vs-apache-kafka\/","og_site_name":"The New Stack","article_publisher":"https:\/\/www.facebook.com\/thenewstack","article_published_time":"2022-01-10T16:08:30+00:00","og_image":[{"width":1999,"height":1303,"url":"https:\/\/cdn.thenewstack.io\/media\/2022\/01\/e6884bbf-image4.jpeg","type":"image\/jpeg"}],"author":"Paul Brebner","twitter_card":"summary_large_image","twitter_creator":"@thenewstack","twitter_site":"@thenewstack","twitter_misc":{"Written by":"Paul Brebner","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/thenewstack.io\/redis-pub-sub-vs-apache-kafka\/#article","isPartOf":{"@id":"https:\/\/thenewstack.io\/redis-pub-sub-vs-apache-kafka\/"},"author":{"name":"Paul Brebner","@id":"https:\/\/thenewstack.io\/#\/schema\/person\/fac61d9018ed7a2f2afe3245eacb13fb"},"headline":"Redis Pub\/Sub vs. Apache Kafka","datePublished":"2022-01-10T16:08:30+00:00","mainEntityOfPage":{"@id":"https:\/\/thenewstack.io\/redis-pub-sub-vs-apache-kafka\/"},"wordCount":1546,"publisher":{"@id":"https:\/\/thenewstack.io\/#organization"},"image":{"@id":"https:\/\/thenewstack.io\/redis-pub-sub-vs-apache-kafka\/#primaryimage"},"thumbnailUrl":"https:\/\/cdn.thenewstack.io\/media\/2022\/01\/e6884bbf-image4.jpeg","keywords":["Contributed","instaclustr","Sponsored","post-contributed"],"articleSection":["Data","Networking","Technology"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/thenewstack.io\/redis-pub-sub-vs-apache-kafka\/","url":"https:\/\/thenewstack.io\/redis-pub-sub-vs-apache-kafka\/","name":"Redis Pub\/Sub vs. Apache Kafka - The New Stack","isPartOf":{"@id":"https:\/\/thenewstack.io\/#website"},"primaryImageOfPage":{"@id":"https:\/\/thenewstack.io\/redis-pub-sub-vs-apache-kafka\/#primaryimage"},"image":{"@id":"https:\/\/thenewstack.io\/redis-pub-sub-vs-apache-kafka\/#primaryimage"},"thumbnailUrl":"https:\/\/cdn.thenewstack.io\/media\/2022\/01\/e6884bbf-image4.jpeg","datePublished":"2022-01-10T16:08:30+00:00","description":"Redis Pub\/Sub sounds like a fairly typical pub\/sub system, but it can do more. Let's compare it to Apache Kafka.","breadcrumb":{"@id":"https:\/\/thenewstack.io\/redis-pub-sub-vs-apache-kafka\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/thenewstack.io\/redis-pub-sub-vs-apache-kafka\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/thenewstack.io\/redis-pub-sub-vs-apache-kafka\/#primaryimage","url":"https:\/\/cdn.thenewstack.io\/media\/2022\/01\/e6884bbf-image4.jpeg","contentUrl":"https:\/\/cdn.thenewstack.io\/media\/2022\/01\/e6884bbf-image4.jpeg","width":1999,"height":1303},{"@type":"BreadcrumbList","@id":"https:\/\/thenewstack.io\/redis-pub-sub-vs-apache-kafka\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/thenewstack.io\/"},{"@type":"ListItem","position":2,"name":"Redis Pub\/Sub vs. Apache Kafka"}]},{"@type":"WebSite","@id":"https:\/\/thenewstack.io\/#website","url":"https:\/\/thenewstack.io\/","name":"The New Stack","description":"","publisher":{"@id":"https:\/\/thenewstack.io\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/thenewstack.io\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/thenewstack.io\/#organization","name":"The New Stack","url":"https:\/\/thenewstack.io\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/thenewstack.io\/#\/schema\/logo\/image\/","url":"https:\/\/cdn.thenewstack.io\/media\/2021\/11\/a9fbec84-the-new-stack-logo-rgb-screen.png","contentUrl":"https:\/\/cdn.thenewstack.io\/media\/2021\/11\/a9fbec84-the-new-stack-logo-rgb-screen.png","width":1032,"height":128,"caption":"The New Stack"},"image":{"@id":"https:\/\/thenewstack.io\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/thenewstack","https:\/\/x.com\/thenewstack"]},{"@type":"Person","@id":"https:\/\/thenewstack.io\/#\/schema\/person\/fac61d9018ed7a2f2afe3245eacb13fb","name":"Paul Brebner","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/ad516503a11cd5ca435acc9bb6523536?s=9615105800a0270a384212262298083881","url":"https:\/\/secure.gravatar.com\/avatar\/ad516503a11cd5ca435acc9bb6523536?s=96","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/ad516503a11cd5ca435acc9bb6523536?s=96","caption":"Paul Brebner"},"sameAs":["https:\/\/www.linkedin.com\/in\/paul-brebner-0a547b4\/"],"url":"https:\/\/thenewstack.io\/author\/paul-brebner\/"}]}},"_links":{"self":[{"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/posts\/20653166","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/users\/1799"}],"replies":[{"embeddable":true,"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/comments?post=20653166"}],"version-history":[{"count":36,"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/posts\/20653166\/revisions"}],"predecessor-version":[{"id":20713272,"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/posts\/20653166\/revisions\/20713272"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/media\/20657258"}],"wp:attachment":[{"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/media?parent=20653166"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/categories?post=20653166"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/tags?post=20653166"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/coauthors?post=20653166"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}