{"id":271,"date":"2026-10-01T11:04:40","date_gmt":"2026-10-01T03:04:40","guid":{"rendered":"https:\/\/yykcj.com\/?p=271"},"modified":"2026-10-01T11:04:40","modified_gmt":"2026-10-01T03:04:40","slug":"redis-%e9%ab%98%e7%ba%a7%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84%e5%ae%9e%e6%88%98%ef%bc%9a%e4%bb%8e-bitmap-%e5%88%b0-stream-%e7%9a%84%e8%90%bd%e5%9c%b0%e6%8c%87%e5%8d%97","status":"publish","type":"post","link":"https:\/\/yykcj.com\/?p=271","title":{"rendered":"Redis \u9ad8\u7ea7\u6570\u636e\u7ed3\u6784\u5b9e\u6218\uff1a\u4ece Bitmap \u5230 Stream \u7684\u843d\u5730\u6307\u5357"},"content":{"rendered":"<h2>\u4e3a\u4ec0\u4e48\u9700\u8981\u9ad8\u7ea7\u6570\u636e\u7ed3\u6784\uff1f<\/h2>\n<p>\u5f88\u591a\u5f00\u53d1\u8005\u5bf9 Redis \u7684\u8ba4\u77e5\u8fd8\u505c\u7559\u5728 String\u3001Hash\u3001List\u3001Set\u3001ZSet \u8fd9\u4e94\u79cd\u57fa\u7840\u7c7b\u578b\u4e0a\u3002\u4f46\u5728\u5b9e\u9645\u751f\u4ea7\u73af\u5883\u4e2d\uff0c\u6211\u4eec\u5e38\u9047\u5230\u4e00\u4e9b\u7279\u6b8a\u9700\u6c42\uff1a<\/p>\n<ul>\n<li>\u7edf\u8ba1\u6bcf\u5929\u4e0a\u4ebf\u7528\u6237\u7684\u6d3b\u8dc3\u60c5\u51b5\uff0c\u4f46\u5185\u5b58\u6709\u9650<\/li>\n<li>\u8ba1\u7b97\u9644\u8fd1\u7684\u4eba\uff0c\u4e14\u8981\u6c42\u6beb\u79d2\u7ea7\u54cd\u5e94<\/li>\n<li>\u5b9e\u73b0\u4e00\u4e2a\u8f7b\u91cf\u7ea7\u6d88\u606f\u961f\u5217\uff0c\u652f\u6301\u591a\u6d88\u8d39\u8005\u7ec4<\/li>\n<li>\u6279\u91cf\u6267\u884c\u547d\u4ee4\uff0c\u51cf\u5c11\u7f51\u7edc\u5f80\u8fd4<\/li>\n<\/ul>\n<p>\u8fd9\u4e9b\u573a\u666f\u5982\u679c\u53ea\u7528\u57fa\u7840\u7c7b\u578b\uff0c\u8981\u4e48\u5b9e\u73b0\u590d\u6742\uff0c\u8981\u4e48\u6027\u80fd\u582a\u5fe7\u3002Redis \u63d0\u4f9b\u4e86\u4e00\u7cfb\u5217\u9ad8\u7ea7\u6570\u636e\u7ed3\u6784\uff0c\u4e13\u95e8\u89e3\u51b3\u8fd9\u7c7b\u95ee\u9898\u3002\u672c\u6587\u5c06\u901a\u8fc7\u4e94\u4e2a\u5b9e\u6218\u6848\u4f8b\uff0c\u5e26\u4f60\u5f7b\u5e95\u638c\u63e1\u5b83\u4eec\u3002<\/p>\n<p>> \u672c\u6587\u4ee3\u7801\u57fa\u4e8e Python 3.8+ \u548c redis-py 4.x\uff0c\u6240\u6709\u793a\u4f8b\u5747\u53ef\u5728\u672c\u5730 Redis \u4e2d\u76f4\u63a5\u8fd0\u884c\u3002<\/p>\n<h2>\u73af\u5883\u51c6\u5907<\/h2>\n<p>\u786e\u4fdd\u5df2\u5b89\u88c5 Redis \u548c Python \u4f9d\u8d56\uff1a<\/p>\n<pre><code class=\"language-bash\">\n# \u5b89\u88c5 Redis\uff08\u7565\uff0c\u8bf7\u53c2\u8003\u5b98\u65b9\u6587\u6863\uff09\n# \u5b89\u88c5 Python \u5ba2\u6237\u7aef\npip install redis\n<\/code><\/pre>\n<p>\u542f\u52a8 Redis \u670d\u52a1\u540e\uff0c\u7528\u4ee5\u4e0b\u4ee3\u7801\u6d4b\u8bd5\u8fde\u63a5\uff1a<\/p>\n<pre><code class=\"language-python\">\nimport redis\nr = redis.Redis(host=&#x27;localhost&#x27;, port=6379, db=0, decode_responses=True)\nprint(r.ping())  # \u8f93\u51fa True \u8868\u793a\u8fde\u63a5\u6210\u529f\n<\/code><\/pre>\n<h2>1. Bitmap\uff1a\u6d77\u91cf\u5e03\u5c14\u7edf\u8ba1\u7684\u5229\u5668<\/h2>\n<h3>\u573a\u666f<\/h3>\n<p>\u5047\u8bbe\u4f60\u8fd0\u8425\u4e00\u4e2a\u65e5\u6d3b\u5343\u4e07\u7684 App\uff0c\u9700\u8981\u7edf\u8ba1\u6bcf\u4e2a\u7528\u6237\u7684\u6bcf\u65e5\u7b7e\u5230\u60c5\u51b5\uff0c\u5e76\u652f\u6301\u5feb\u901f\u67e5\u8be2\u67d0\u7528\u6237\u67d0\u5929\u662f\u5426\u7b7e\u5230\u3001\u67d0\u5929\u603b\u7b7e\u5230\u4eba\u6570\u3001\u8fde\u7eed\u7b7e\u5230\u5929\u6570\u7b49\u3002\u7528 Set \u5b58\u50a8\uff0c\u6bcf\u4e2a\u7528\u6237 ID \u5360 8 \u5b57\u8282\uff0c\u4e00\u5343\u4e07\u7528\u6237\u5c31\u662f 80MB\uff0c\u4e00\u4e2a\u6708\u5c31\u662f 2.4GB\u3002\u800c Bitmap \u6bcf\u4e2a\u7528\u6237\u53ea\u5360 1 bit\uff0c\u5185\u5b58\u8282\u7701 64 \u500d\u3002<\/p>\n<h3>\u6838\u5fc3\u547d\u4ee4<\/h3>\n<ul>\n<li><code>SETBIT key offset value<\/code>\uff1a\u8bbe\u7f6e\u67d0\u4e00\u4f4d\u4e3a 0 \u6216 1<\/li>\n<li><code>GETBIT key offset<\/code>\uff1a\u83b7\u53d6\u67d0\u4e00\u4f4d\u7684\u503c<\/li>\n<li><code>BITCOUNT key [start end]<\/code>\uff1a\u7edf\u8ba1\u4e3a 1 \u7684\u4f4d\u6570<\/li>\n<li><code>BITOP operation destkey key [key ...]<\/code>\uff1a\u4f4d\u8fd0\u7b97\uff08AND\/OR\/XOR\/NOT\uff09<\/li>\n<\/ul>\n<h3>\u5b9e\u6218\uff1a\u7528\u6237\u7b7e\u5230\u7cfb\u7edf<\/h3>\n<pre><code class=\"language-python\">\nimport redis\nfrom datetime import date\n\nr = redis.Redis(decode_responses=True)\n\ndef sign_in(user_id, day=None):\n    &quot;&quot;&quot;\u7528\u6237\u7b7e\u5230\uff0cday \u683c\u5f0f YYYYMMDD\uff0c\u9ed8\u8ba4\u4e3a\u4eca\u5929&quot;&quot;&quot;\n    if day is None:\n        day = date.today().strftime(&#x27;%Y%m%d&#x27;)\n    key = f&#x27;sign:{day}&#x27;\n    # \u7528\u6237 ID \u4f5c\u4e3a offset\uff0c\u5047\u8bbe\u7528\u6237 ID \u4ece 1 \u5f00\u59cb\n    r.setbit(key, user_id, 1)\n\ndef is_signed(user_id, day):\n    &quot;&quot;&quot;\u68c0\u67e5\u67d0\u5929\u662f\u5426\u7b7e\u5230&quot;&quot;&quot;\n    key = f&#x27;sign:{day}&#x27;\n    return r.getbit(key, user_id) == 1\n\ndef count_signs(day):\n    &quot;&quot;&quot;\u7edf\u8ba1\u67d0\u5929\u7b7e\u5230\u603b\u4eba\u6570&quot;&quot;&quot;\n    key = f&#x27;sign:{day}&#x27;\n    return r.bitcount(key)\n\ndef continuous_days(user_id, end_day):\n    &quot;&quot;&quot;\u8ba1\u7b97\u622a\u81f3 end_day \u7684\u8fde\u7eed\u7b7e\u5230\u5929\u6570\uff08\u9700\u4ece\u5f53\u5929\u5411\u524d\u68c0\u67e5\uff09&quot;&quot;&quot;\n    from datetime import datetime, timedelta\n    end = datetime.strptime(end_day, &#x27;%Y%m%d&#x27;)\n    days = 0\n    while True:\n        day_str = end.strftime(&#x27;%Y%m%d&#x27;)\n        if is_signed(user_id, day_str):\n            days += 1\n            end -= timedelta(days=1)\n        else:\n            break\n    return days\n\n# \u6d4b\u8bd5\nsign_in(1001, &#x27;20250301&#x27;)\nsign_in(1001, &#x27;20250302&#x27;)\nsign_in(1001, &#x27;20250303&#x27;)\nprint(is_signed(1001, &#x27;20250302&#x27;))  # True\nprint(count_signs(&#x27;20250303&#x27;))      # 1\nprint(continuous_days(1001, &#x27;20250303&#x27;))  # 3\n<\/code><\/pre>\n<p><strong>\u6ce8\u610f<\/strong>\uff1aBitmap \u7684 offset \u6700\u5927\u4e3a 2^32-1\uff08512MB\uff09\uff0c\u5982\u679c\u7528\u6237 ID \u7a00\u758f\u4e14\u8303\u56f4\u6781\u5927\uff0c\u4f1a\u9020\u6210\u5927\u91cf\u5185\u5b58\u6d6a\u8d39\u3002\u6b64\u65f6\u5efa\u8bae\u7528 Hash \u5206\u7247\u6216\u6539\u7528\u5176\u4ed6\u65b9\u6848\u3002<\/p>\n<p><strong>\ud83d\udca1 \u6700\u4f73\u5b9e\u8df5<\/strong>\uff1a\u5bf9\u4e8e\u6309\u6708\u7edf\u8ba1\uff0c\u53ef\u4ee5\u7528 <code>BITOP AND<\/code> \u8ba1\u7b97\u8fde\u7eed\u7b7e\u5230\u7528\u6237\u3002\u4f8b\u5982 <code>BITOP AND dest sign:20250301 sign:20250302<\/code> \u5f97\u5230\u4e24\u5929\u90fd\u7b7e\u5230\u7684\u7528\u6237\u4f4d\u56fe\u3002<\/p>\n<h2>2. HyperLogLog\uff1a\u4e0d\u7cbe\u786e\u4f46\u6781\u7701\u5185\u5b58\u7684\u57fa\u6570\u7edf\u8ba1<\/h2>\n<h3>\u573a\u666f<\/h3>\n<p>\u7edf\u8ba1\u7f51\u7ad9\u6bcf\u65e5 UV\uff08\u72ec\u7acb\u8bbf\u5ba2\uff09\uff0c\u5982\u679c\u4f7f\u7528 Set \u5b58\u50a8\u7528\u6237 ID\uff0c\u4e00\u4ebf\u7528\u6237\u9700\u8981\u7ea6 800MB\u3002\u800c HyperLogLog \u53ea\u9700\u8981 12KB\uff0c\u8bef\u5dee\u7387\u4ec5 0.81%\u3002\u5bf9\u4e8e\u4e0d\u9700\u8981\u7cbe\u786e\u503c\u7684\u7edf\u8ba1\u573a\u666f\uff0c\u8fd9\u662f\u7edd\u4f73\u9009\u62e9\u3002<\/p>\n<h3>\u6838\u5fc3\u547d\u4ee4<\/h3>\n<ul>\n<li><code>PFADD key element [element ...]<\/code>\uff1a\u6dfb\u52a0\u5143\u7d20<\/li>\n<li><code>PFCOUNT key [key ...]<\/code>\uff1a\u8fd4\u56de\u57fa\u6570\u4f30\u8ba1\u503c<\/li>\n<li><code>PFMERGE destkey sourcekey [sourcekey ...]<\/code>\uff1a\u5408\u5e76\u591a\u4e2a HyperLogLog<\/li>\n<\/ul>\n<h3>\u5b9e\u6218\uff1aUV \u7edf\u8ba1<\/h3>\n<pre><code class=\"language-python\">\ndef add_uv(day, user_id):\n    key = f&#x27;uv:{day}&#x27;\n    r.pfadd(key, user_id)\n\ndef get_uv(day):\n    return r.pfcount(f&#x27;uv:{day}&#x27;)\n\ndef get_uv_range(days):\n    &quot;&quot;&quot;\u7edf\u8ba1\u591a\u5929\u603b UV\uff08\u53bb\u91cd\uff09&quot;&quot;&quot;\n    keys = [f&#x27;uv:{day}&#x27; for day in days]\n    return r.pfcount(*keys)\n\n# \u6a21\u62df\u6dfb\u52a0 10000 \u4e2a\u7528\u6237\nfor i in range(10000):\n    add_uv(&#x27;20250303&#x27;, f&#x27;user_{i}&#x27;)\nprint(get_uv(&#x27;20250303&#x27;))  # \u7ea6 10000\uff0c\u53ef\u80fd\u6709\u5fae\u5c0f\u8bef\u5dee\n<\/code><\/pre>\n<p><strong>\u6ce8\u610f<\/strong>\uff1aHyperLogLog \u4e0d\u5b58\u50a8\u5143\u7d20\u672c\u8eab\uff0c\u53ea\u7528\u4e8e\u8ba1\u6570\uff0c\u4e14\u65e0\u6cd5\u5224\u65ad\u67d0\u4e2a\u5143\u7d20\u662f\u5426\u5b58\u5728\u3002\u5982\u679c\u9700\u8981\u540c\u65f6\u5224\u65ad\u5b58\u5728\u6027\uff0c\u5e94\u7ed3\u5408 Bloom Filter\uff08Redis \u6a21\u5757\uff09\u6216 Set\u3002<\/p>\n<p><strong>\ud83d\udca1 \u6700\u4f73\u5b9e\u8df5<\/strong>\uff1aHyperLogLog \u9002\u5408\u7edf\u8ba1\u5927\u89c4\u6a21\u53bb\u91cd\u8ba1\u6570\uff0c\u5982 UV\u3001\u641c\u7d22\u5173\u952e\u8bcd\u53bb\u91cd\u6570\u3002\u4f46\u8981\u6ce8\u610f\u5b83\u4e0d\u4fdd\u8bc1\u7cbe\u786e\uff0c\u5982\u679c\u4e1a\u52a1\u8981\u6c42 100% \u51c6\u786e\uff0c\u8bf7\u4f7f\u7528 Set \u6216 Sorted Set\u3002<\/p>\n<h2>3. GEO\uff1a\u5730\u7406\u4f4d\u7f6e\u8ba1\u7b97<\/h2>\n<h3>\u573a\u666f<\/h3>\n<p>\u201c\u9644\u8fd1\u7684\u4eba\u201d\u3001\u201c\u9644\u8fd1\u7684\u9910\u5385\u201d\u662f\u5e38\u89c1\u9700\u6c42\u3002Redis \u7684 GEO \u57fa\u4e8e Sorted Set \u5b9e\u73b0\uff0c\u652f\u6301\u5b58\u50a8\u7ecf\u7eac\u5ea6\u3001\u8ba1\u7b97\u8ddd\u79bb\u3001\u6309\u534a\u5f84\u67e5\u8be2\u3002<\/p>\n<h3>\u6838\u5fc3\u547d\u4ee4<\/h3>\n<ul>\n<li><code>GEOADD key longitude latitude member<\/code>\uff1a\u6dfb\u52a0\u4f4d\u7f6e<\/li>\n<li><code>GEODIST key member1 member2 [unit]<\/code>\uff1a\u8ba1\u7b97\u8ddd\u79bb<\/li>\n<li><code>GEOSEARCH key FROMMEMBER member BYRADIUS radius unit<\/code>\uff1a\u534a\u5f84\u641c\u7d22<\/li>\n<li><code>GEOPOS key member<\/code>\uff1a\u83b7\u53d6\u5750\u6807<\/li>\n<\/ul>\n<h3>\u5b9e\u6218\uff1a\u9644\u8fd1\u5546\u5bb6\u67e5\u8be2<\/h3>\n<pre><code class=\"language-python\">\ndef add_shop(shop_id, lng, lat):\n    r.geoadd(&#x27;shops&#x27;, (lng, lat, shop_id))\n\ndef nearby_shops(lng, lat, radius_km, count=10):\n    &quot;&quot;&quot;\u67e5\u8be2\u9644\u8fd1\u5546\u5bb6\uff0c\u6309\u8ddd\u79bb\u6392\u5e8f&quot;&quot;&quot;\n    results = r.geosearch(\n        &#x27;shops&#x27;,\n        longitude=lng,\n        latitude=lat,\n        radius=radius_km,\n        unit=&#x27;km&#x27;,\n        sort=&#x27;ASC&#x27;,\n        count=count,\n        withdist=True,\n        withcoord=True\n    )\n    return results\n\n# \u6dfb\u52a0\u51e0\u4e2a\u5317\u4eac\u5730\u6807\nadd_shop(&#x27;tiananmen&#x27;, 116.397, 39.909)\nadd_shop(&#x27;wangfujing&#x27;, 116.410, 39.915)\nadd_shop(&#x27;sanlitun&#x27;, 116.455, 39.933)\n\n# \u67e5\u8be2\u5929\u5b89\u95e8\u9644\u8fd1 5km \u7684\u5546\u5bb6\nprint(nearby_shops(116.397, 39.909, 5))\n# \u8f93\u51fa\u7c7b\u4f3c\uff1a[[&#x27;tiananmen&#x27;, 0.0, [116.397, 39.909]], [&#x27;wangfujing&#x27;, 1.2, [116.410, 39.915]], ...]\n<\/code><\/pre>\n<p><strong>\u6ce8\u610f<\/strong>\uff1aGEO \u7684\u5e95\u5c42\u662f ZSet\uff0c\u6240\u4ee5\u53ef\u4ee5\u7528 <code>ZREM<\/code> \u5220\u9664\u5143\u7d20\u3002\u53e6\u5916\uff0cGEO \u7684\u7cbe\u5ea6\u53d7\u9650\u4e8e geohash \u7f16\u7801\uff0c\u8ddd\u79bb\u8ba1\u7b97\u53ef\u80fd\u6709\u5fae\u5c0f\u8bef\u5dee\u3002<\/p>\n<p><strong>\ud83d\udca1 \u6700\u4f73\u5b9e\u8df5<\/strong>\uff1a\u5bf9\u4e8e\u6d77\u91cf\u4f4d\u7f6e\u6570\u636e\uff0c\u5efa\u8bae\u6309\u57ce\u5e02\u6216\u533a\u57df\u5206 key\uff0c\u907f\u514d\u5355\u4e2a key \u8fc7\u5927\u3002\u540c\u65f6\uff0c\u53ef\u4ee5\u7ed3\u5408 <code>GEORADIUS<\/code> \u7684 <code>STORE<\/code> \u9009\u9879\u5c06\u7ed3\u679c\u5b58\u5165\u65b0 key \u4f9b\u540e\u7eed\u4f7f\u7528\u3002<\/p>\n<h2>4. Stream\uff1a\u8f7b\u91cf\u7ea7\u6d88\u606f\u961f\u5217<\/h2>\n<h3>\u573a\u666f<\/h3>\n<p>\u9700\u8981\u5b9e\u73b0\u4e00\u4e2a\u7b80\u5355\u7684\u6d88\u606f\u961f\u5217\uff0c\u652f\u6301\u591a\u6d88\u8d39\u8005\u3001\u6d88\u606f\u6301\u4e45\u5316\u3001ACK \u673a\u5236\uff0c\u4f46\u53c8\u4e0d\u60f3\u5f15\u5165 Kafka \u6216 RabbitMQ\u3002Redis 5.0 \u5f15\u5165\u7684 Stream \u6b63\u662f\u4e3a\u6b64\u8bbe\u8ba1\u3002<\/p>\n<h3>\u6838\u5fc3\u547d\u4ee4<\/h3>\n<ul>\n<li><code>XADD key <em> field value ...<\/code>\uff1a\u6dfb\u52a0\u6d88\u606f\uff0c<code><\/em><\/code> \u8868\u793a\u81ea\u52a8\u751f\u6210 ID<\/li>\n<li><code>XREADGROUP GROUP group consumer [COUNT n] [BLOCK ms] STREAMS key ><\/code>\uff1a\u6d88\u8d39\u8005\u7ec4\u8bfb\u53d6<\/li>\n<li><code>XACK key group id<\/code>\uff1a\u786e\u8ba4\u6d88\u606f<\/li>\n<li><code>XPENDING key group<\/code>\uff1a\u67e5\u770b\u5f85\u5904\u7406\u6d88\u606f<\/li>\n<li><code>XCLAIM key group consumer min-idle-time id<\/code>\uff1a\u8f6c\u79fb\u6d88\u606f\u6240\u6709\u6743<\/li>\n<\/ul>\n<h3>\u5b9e\u6218\uff1a\u8ba2\u5355\u5904\u7406\u961f\u5217<\/h3>\n<pre><code class=\"language-python\">\nimport time\n\ndef produce_order(order_id):\n    msg_id = r.xadd(&#x27;orders&#x27;, {&#x27;order_id&#x27;: order_id, &#x27;status&#x27;: &#x27;pending&#x27;})\n    return msg_id\n\ndef consume_orders(group, consumer, count=1, block=5000):\n    &quot;&quot;&quot;\u4ece\u6d88\u8d39\u8005\u7ec4\u8bfb\u53d6\u6d88\u606f\uff0cblock \u6beb\u79d2\u8d85\u65f6&quot;&quot;&quot;\n    # \u521b\u5efa\u6d88\u8d39\u8005\u7ec4\uff08\u5982\u679c\u4e0d\u5b58\u5728\uff09\n    try:\n        r.xgroup_create(&#x27;orders&#x27;, group, id=&#x27;0&#x27;, mkstream=True)\n    except redis.exceptions.ResponseError as e:\n        if &#x27;BUSYGROUP&#x27; not in str(e):\n            raise\n    \n    messages = r.xreadgroup(group, consumer, {&#x27;orders&#x27;: &#x27;&gt;&#x27;}, count=count, block=block)\n    if not messages:\n        return []\n    \n    # \u5904\u7406\u6d88\u606f\n    results = []\n    for stream, msgs in messages:\n        for msg_id, fields in msgs:\n            # \u6a21\u62df\u4e1a\u52a1\u5904\u7406\n            print(f&quot;\u5904\u7406\u8ba2\u5355 {fields[&#x27;order_id&#x27;]}&quot;)\n            results.append((msg_id, fields))\n            # \u5904\u7406\u6210\u529f\u540e ACK\n            r.xack(&#x27;orders&#x27;, group, msg_id)\n    return results\n\n# \u751f\u4ea7 5 \u6761\u6d88\u606f\nfor i in range(5):\n    produce_order(f&#x27;ORDER_{i}&#x27;)\n\n# \u6d88\u8d39\u8005 A \u6d88\u8d39\nconsume_orders(&#x27;order_group&#x27;, &#x27;consumer_A&#x27;, count=3)\n# \u6d88\u8d39\u8005 B \u6d88\u8d39\u5269\u4f59\nconsume_orders(&#x27;order_group&#x27;, &#x27;consumer_B&#x27;, count=3)\n<\/code><\/pre>\n<p><strong>\u6ce8\u610f<\/strong>\uff1a<code>XREADGROUP<\/code> \u4f7f\u7528 <code>><\/code> \u8868\u793a\u53ea\u8bfb\u53d6\u65b0\u6d88\u606f\uff0c\u5df2\u6295\u9012\u4f46\u672a ACK \u7684\u6d88\u606f\u4e0d\u4f1a\u518d\u6b21\u6295\u9012\u3002\u5982\u679c\u9700\u8981\u91cd\u65b0\u5904\u7406\u5931\u8d25\u6d88\u606f\uff0c\u9700\u7528 <code>XPENDING<\/code> + <code>XCLAIM<\/code> \u6216 <code>XAUTOCLAIM<\/code>\u3002<\/p>\n<p><strong>\ud83d\udca1 \u6700\u4f73\u5b9e\u8df5<\/strong>\uff1a<\/p>\n<ul>\n<li>\u4e3a\u6d88\u606f\u8bbe\u7f6e\u6700\u5927\u957f\u5ea6\uff1a<code>XADD orders MAXLEN ~ 10000 * ...<\/code> \u907f\u514d\u5185\u5b58\u65e0\u9650\u589e\u957f\u3002<\/li>\n<li>\u4f7f\u7528 <code>XAUTOCLAIM<\/code> \u81ea\u52a8\u8f6c\u79fb\u8d85\u65f6\u672a ACK \u7684\u6d88\u606f\uff0c\u5b9e\u73b0\u6545\u969c\u6062\u590d\u3002<\/li>\n<li>\u6d88\u8d39\u8005\u7ec4\u540d\u79f0\u548c\u6d88\u8d39\u8005\u540d\u79f0\u5e94\u6709\u610f\u4e49\uff0c\u4fbf\u4e8e\u76d1\u63a7\u3002<\/li>\n<\/ul>\n<h2>5. Pipeline\uff1a\u6279\u91cf\u6267\u884c\u4e0e\u6027\u80fd\u4f18\u5316<\/h2>\n<h3>\u573a\u666f<\/h3>\n<p>\u5f53\u9700\u8981\u6267\u884c\u5927\u91cf Redis \u547d\u4ee4\u65f6\uff0c\u6bcf\u4e2a\u547d\u4ee4\u4e00\u6b21\u7f51\u7edc\u5f80\u8fd4\uff08RTT\uff09\u4f1a\u6210\u4e3a\u74f6\u9888\u3002Pipeline \u5141\u8bb8\u4e00\u6b21\u6027\u53d1\u9001\u591a\u6761\u547d\u4ee4\uff0c\u51cf\u5c11\u7f51\u7edc\u5f00\u9500\u3002<\/p>\n<h3>\u5b9e\u6218\uff1a\u6279\u91cf\u63d2\u5165\u4e0e\u67e5\u8be2<\/h3>\n<pre><code class=\"language-python\">\ndef batch_set(keys_values):\n    &quot;&quot;&quot;\u6279\u91cf\u8bbe\u7f6e\u952e\u503c\u5bf9&quot;&quot;&quot;\n    pipe = r.pipeline(transaction=False)  # \u975e\u4e8b\u52a1\u6a21\u5f0f\uff0c\u6027\u80fd\u66f4\u9ad8\n    for key, value in keys_values:\n        pipe.set(key, value)\n    return pipe.execute()\n\ndef batch_get(keys):\n    &quot;&quot;&quot;\u6279\u91cf\u83b7\u53d6&quot;&quot;&quot;\n    pipe = r.pipeline(transaction=False)\n    for key in keys:\n        pipe.get(key)\n    return pipe.execute()\n\n# \u6d4b\u8bd5\nkv = [(f&#x27;key_{i}&#x27;, f&#x27;value_{i}&#x27;) for i in range(1000)]\nbatch_set(kv)\nvalues = batch_get([f&#x27;key_{i}&#x27; for i in range(1000)])\nprint(len(values))  # 1000\n<\/code><\/pre>\n<p><strong>\u6ce8\u610f<\/strong>\uff1aPipeline \u4e0d\u4fdd\u8bc1\u539f\u5b50\u6027\uff08\u9664\u975e\u4f7f\u7528 <code>transaction=True<\/code>\uff09\uff0c\u547d\u4ee4\u6309\u987a\u5e8f\u6267\u884c\uff0c\u4f46\u4e2d\u95f4\u53ef\u80fd\u63d2\u5165\u5176\u4ed6\u5ba2\u6237\u7aef\u7684\u547d\u4ee4\u3002\u5982\u679c\u4e1a\u52a1\u9700\u8981\u539f\u5b50\u6027\uff0c\u8bf7\u4f7f\u7528 <code>MULTI\/EXEC<\/code> \u4e8b\u52a1\u6216 Lua \u811a\u672c\u3002<\/p>\n<p><strong>\ud83d\udca1 \u6700\u4f73\u5b9e\u8df5<\/strong>\uff1a<\/p>\n<ul>\n<li>\u63a7\u5236\u5355\u6b21 Pipeline \u7684\u547d\u4ee4\u6570\u91cf\uff08\u5efa\u8bae 500-1000 \u6761\uff09\uff0c\u907f\u514d\u963b\u585e Redis \u548c\u5ba2\u6237\u7aef\u5185\u5b58\u6ea2\u51fa\u3002<\/li>\n<li>\u5bf9\u4e8e\u53ea\u8bfb\u573a\u666f\uff0c\u53ef\u4ee5\u7ed3\u5408 <code>CLIENT REPLY OFF<\/code> \u8fdb\u4e00\u6b65\u51cf\u5c11\u7f51\u7edc\u6d41\u91cf\u3002<\/li>\n<\/ul>\n<h2>\u603b\u7ed3<\/h2>\n<p>\u672c\u6587\u4ecb\u7ecd\u4e86 Redis \u4e94\u79cd\u9ad8\u7ea7\u6570\u636e\u7ed3\u6784\u53ca\u5176\u5178\u578b\u5e94\u7528\u573a\u666f\uff1a<\/p>\n<p>| \u6570\u636e\u7ed3\u6784 | \u9002\u7528\u573a\u666f | \u5185\u5b58\/\u6027\u80fd\u7279\u70b9 | |&#8212;&#8212;&#8212;|&#8212;&#8212;&#8212;|&#8212;&#8212;&#8212;&#8212;&#8211;| | Bitmap | \u5e03\u5c14\u7edf\u8ba1\u3001\u7b7e\u5230 | \u6781\u7701\u5185\u5b58\uff0c\u652f\u6301\u4f4d\u8fd0\u7b97 | | HyperLogLog | \u57fa\u6570\u7edf\u8ba1\uff08UV\uff09 | \u56fa\u5b9a 12KB\uff0c\u8bef\u5dee 0.81% | | GEO | \u5730\u7406\u4f4d\u7f6e | \u57fa\u4e8e ZSet\uff0c\u652f\u6301\u534a\u5f84\u641c\u7d22 | | Stream | \u6d88\u606f\u961f\u5217 | \u6301\u4e45\u5316\u3001\u6d88\u8d39\u8005\u7ec4\u3001ACK | | Pipeline | \u6279\u91cf\u64cd\u4f5c | \u51cf\u5c11 RTT\uff0c\u63d0\u5347\u541e\u5410 |<\/p>\n<p>\u5728\u5b9e\u9645\u9879\u76ee\u4e2d\uff0c\u5f80\u5f80\u9700\u8981\u7ec4\u5408\u4f7f\u7528\u3002\u4f8b\u5982\uff0c\u7528 Bitmap \u8bb0\u5f55\u7528\u6237\u7b7e\u5230\uff0c\u7528 HyperLogLog \u7edf\u8ba1 UV\uff0c\u7528 GEO \u5b9e\u73b0\u9644\u8fd1\u67e5\u8be2\uff0c\u7528 Stream \u5904\u7406\u5f02\u6b65\u4efb\u52a1\uff0c\u7528 Pipeline \u4f18\u5316\u6279\u91cf\u5199\u5165\u3002<\/p>\n<p><strong>\u4e0b\u4e00\u6b65\u5b66\u4e60\u5efa\u8bae<\/strong>\uff1a<\/p>\n<ul>\n<li>\u6df1\u5165\u4e86\u89e3 Redis \u6a21\u5757\uff08\u5982 RedisBloom\u3001RedisJSON\uff09<\/li>\n<li>\u5b66\u4e60 Lua \u811a\u672c\u5b9e\u73b0\u539f\u5b50\u64cd\u4f5c<\/li>\n<li>\u7814\u7a76 Redis \u6301\u4e45\u5316\uff08RDB\/AOF\uff09\u4e0e\u96c6\u7fa4\u65b9\u6848<\/li>\n<\/ul>\n<p>\u5e0c\u671b\u672c\u6587\u80fd\u5e2e\u52a9\u4f60\u5728\u5b9e\u9645\u5de5\u4f5c\u4e2d\u66f4\u597d\u5730\u5229\u7528 Redis\u3002\u5982\u679c\u6709\u4efb\u4f55\u95ee\u9898\uff0c\u6b22\u8fce\u7559\u8a00\u8ba8\u8bba\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u672c\u6587\u6df1\u5165\u8bb2\u89e3 Redis \u4e94\u79cd\u9ad8\u7ea7\u6570\u636e\u7ed3\u6784\uff08Bitmap\u3001HyperLogLog\u3001GEO\u3001Stream\u3001Pipeline\uff09\u7684\u6838\u5fc3\u539f\u7406\u3001\u5178\u578b\u5e94\u7528\u573a\u666f\uff0c\u5e76\u63d0\u4f9b\u53ef\u76f4\u63a5\u8fd0\u884c\u7684 Python \u4ee3\u7801\u793a\u4f8b\u3002\u901a\u8fc7\u672c\u6587\uff0c\u4f60\u5c06\u638c\u63e1\u5982\u4f55\u7528 Redis \u89e3\u51b3\u6d77\u91cf\u6570\u636e\u7edf\u8ba1\u3001\u5730\u7406\u4f4d\u7f6e\u3001\u6d88\u606f\u961f\u5217\u7b49\u5b9e\u9645\u95ee\u9898\u3002<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,4],"tags":[65,66,6,251,126],"class_list":["post-271","post","type-post","status-publish","format-standard","hentry","category-3","category-4","tag-redis","tag-66","tag-6","tag-251","tag-126"],"_links":{"self":[{"href":"https:\/\/yykcj.com\/index.php?rest_route=\/wp\/v2\/posts\/271","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/yykcj.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/yykcj.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/yykcj.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/yykcj.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=271"}],"version-history":[{"count":0,"href":"https:\/\/yykcj.com\/index.php?rest_route=\/wp\/v2\/posts\/271\/revisions"}],"wp:attachment":[{"href":"https:\/\/yykcj.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=271"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/yykcj.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=271"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/yykcj.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=271"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}