【Redis深度专题】「核心技术提升」从源码角度探究Redis服务的内存使用、清理以及逐出等底层实现原理

背景介绍

Redis作为一种高性能的内存NoSQL数据库,其容量受限于最大内存的限制。用户在使用阿里云Redis时,除了对性能和稳定性有较高的要求外,对内存占用也非常敏感。然而,在实际使用中,一些用户可能会发现他们的线上实例的内存占用比预期的要大。

内存较高的场景

在使用Redis时,以下是一些可能导致内存占用较高的因素:

  • 数据存储格式:Redis支持不同的数据结构,如字符串、哈希、列表等。不同数据结构的存储方式和编码格式可能会导致不同的内存占用。确保选择合适的数据结构和存储方式,可以有效地控制内存占用。

  • 数据过期时间:Redis允许为存储的数据设置过期时间。如果数据没有正确设置过期时间或过期时间设置不合理,可能会导致数据过多地积累在内存中,从而增加了内存占用。

  • 内存碎片化:Redis使用内存分配机制来存储数据,而这可能导致内存碎片化。当有键过期或被删除时,内存不会立即释放,而是会留下一些碎片空间。内存碎片化可能导致总体内存占用率的增加。

降低Redis的内存占用

通过合理的数据结构选择、设置合理的数据过期时间和优化内存使用等措施,可以帮助降低Redis的内存占用,提高性能和稳定性。定期监控和优化内存使用是持续保持Redis在高性能和低内存占用之间平衡的关键。

  • 优化数据结构和存储方式:根据实际需求选择合适的数据结构和对应的存储方式,例如使用压缩列表来存储较短的列表。

  • 合理设置数据过期时间:为存储的数据设置合适的过期时间,确保数据按需进行过期,并及时释放内存空间。

  • 使用字节淘汰机制:配置合适的内存淘汰机制,以便及时回收和释放过期数据和不活跃数据占用的内存空间。

  • 监控和优化内存使用:定期监控Redis实例的内存使用情况,及时发现和解决占用较高的问题,并进行适当的调优。

额外内存较高的场景

实际上,在Redis实例中,除了保存原始键值对所需的内存开销之外,还存在一些运行时产生的额外内存开销。其中,两个主要因素是:

  • 垃圾数据和过期键所占空间:在Redis中,当键被删除或过期时,并不会立即释放相应的内存空间。因此,即使键已过期或被删除,仍然会占用内存空间,这可能导致垃圾数据和过期键占据内存。

  • 渐进式Rehash导致的未及时删除:当Redis进行渐进式Rehash过程时,会在新哈希槽中分配内存空间,并逐步迁移旧哈希槽中的键。然而,在迁移期间,如果有新的写入操作,可能会导致旧哈希槽中的键未被及时删除,从而占据了额外的内存空间。

为了优化和降低Redis实例的内存占用,可以考虑以下优化措施:

定期清理垃圾数据和过期键

通过适当设置数据的过期时间,或使用定期任务进行清理操作,及时清理过期的键和垃圾数据,以释放占用的内存空间。

执行Rehash后进行内存回收

在Redis执行Rehash或使用槽位分配器时,可以通过执行KEYS命令或使用SCAN迭代器等方式,确保未及时迁移的键被删除,从而释放旧哈希槽中的内存空间。

监控和优化Redis的内存使用情况是关键。定期检查内存占用,并根据需求进行调整和优化,有助于提高Redis实例的性能和稳定性,并避免额外的内存开销。同时,合理设置键的过期时间,可以避免不必要的内存占用

渐进式Rehash操作

Redis中的字典渐进式Rehash是指在字典扩容时,Redis会逐步迁移旧的哈希桶中的键值对到新的更大的哈希桶中的过程。

渐进式Rehash操作的原因

会出现渐进式Rehash的原因是当字典中的键值对数量增加时,为了保持哈希表的性能,Redis会定期扩容字典。而在字典扩容的过程中,Redis会同时创建一个新的更大的哈希桶,并将旧哈希桶中的键值对逐步迁移到新的哈希桶中。

具体的渐进式Rehash过程

渐进式Rehash,Redis可以避免在一次性进行哈希桶迁移时造成的性能问题,同时可以保证旧的哈希桶仍然可以被正常访问。

  1. Redis在旧哈希桶中选择一个非空的桶进行rehash。

  2. 将选择的桶中的键值对逐个迁移到新的哈希桶中。

  3. 在迁移的过程中,对于新哈希桶中的每个桶,将新桶指向旧桶的下一个桶,使得迁移的键值对能够被访问到。

  4. 当选择的桶中的所有键值对都迁移到新哈希桶后,将旧哈希桶删除。

  5. 重复以上步骤,直到所有的桶都被迁移到新哈希桶中。

渐进式Rehash可以在很长的时间内进行,逐渐将键值对从旧哈希桶迁移到新哈希桶,减少了操作的复杂性和对性能的影响。

其他方面开销

Redis在管理数据时涉及到底层数据结构的开销、客户端信息和读写缓冲区等方面的管理。此外,在Redis的主从复制过程中,进行bgsave操作可能会产生一些额外开销。

  • 客户端信息管理:在使用Redis时,应合理管理客户端的连接和会话信息。避免创建过多的无效连接或长时间闲置的连接,以减轻服务器负载,并提高资源利用率。

  • 读写缓冲区管理:在数据读写过程中,Redis使用缓冲区来提高性能。可以通过适当配置缓冲区的大小和处理策略,以平衡内存使用和性能需求。根据实际情况,可以调整Redis的配置参数,如 client-output-buffer-limitclient-query-buffer-limit,以优化缓冲区管理。

  • Redis主从复制:在Redis的主从复制过程中,进行bgsave操作可能会导致额外的开销,因为bgsave会将数据快照保存到磁盘中。为了减少对主节点的影响,可以考虑在从节点上执行bgsave操作,避免主节点的性能影响。此外,合理设置Redis的复制策略和配置参数可对主从复制效率进行优化。

Redis过期数据清理策略

为了避免大量过期键的一次性清理对Redis服务性能造成负面影响,Redis已经优化,在空闲时清理过期键。这种策略可以有效减少对服务性能的干扰,使得清理工作更加平稳和高效。

过期数据清理时机

  1. Redis在逐出过期键时,具体的时机是在访问键时进行判断,如果发现键已过期,则将其逐出。这种机制确保了对过期键的及时清理,同时也保证了数据访问时的高效性和实时性。
robj *lookupKeyRead(redisDb *db, robj *key) {robj *val;expireIfNeeded(db,key);val = lookupKey(db,key);...return val;
}
  1. 在CPU空闲时,定期的serverCron任务会逐出部分过期的Key。
aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL)int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {...databasesCron();...}void databasesCron(void) {/* Expire keys by random sampling. Not required for slaves+ as master will synthesize DELs for us. */if (server.active_expire_enabled && server.masterhost == NULL)activeExpireCycle(ACTIVE_EXPIRE_CYCLE_SLOW);...}
}
  1. 每次事件循环执行时,会逐出部分过期的Key。
        void aeMain(aeEventLoop *eventLoop) {eventLoop->stop = 0;while (!eventLoop->stop) {if (eventLoop->beforesleep != NULL)eventLoop->beforesleep(eventLoop);aeProcessEvents(eventLoop, AE_ALL_EVENTS);}}void beforeSleep(struct aeEventLoop *eventLoop) {.../* Run a fast expire cycle (the called function will return- ASAP if a fast cycle is not needed). */if (server.active_expire_enabled && server.masterhost == NULL)activeExpireCycle(ACTIVE_EXPIRE_CYCLE_FAST);...}

过期数据清理算法

通过动态调整清理频率、引入并行化处理机制、优化内存碎片整理策略以及持续监控和优化系统性能,可以有效提升Redis过期Key清理的性能,并在不影响正常服务的情况下实现长时间服务的性能最优化。

优化方案分析
  • 根据系统负载和流量特征调整定时清理的频率:通过监控系统负载和Key的过期频率,动态调整清理的时间间隔,确保能够及时清理过期Key,同时避免频繁的清理操作影响正常服务。

  • 通过合理设置最大时间限制并进行并行处理: 针对清理操作的最大时间限制,可以引入并行化处理机制,将清理操作分批进行,并行处理以提高清理效率,可以确保清理操作在限定时间内完成,并且不会对正常服务产生明显影响。

  • 通过合理设置Redis的内存碎片整理策略:可以减少内存碎片对过期Key清理效率的影响,进一步优化清理性能。

  • 建议监控系统的运行情况:定期检查系统的清理效率和对服务的影响程度,并根据实际情况进行调整和优化,以确保系统长时间运行时的性能最优。

清理数据具体的流程
  1. Redis配置项 hz,定义了 serverCron 任务的执行周期,默认为 10,即在 CPU 空闲时每秒执行 10 次。

  2. 每次过期键清理的时间不超过 CPU 时间的 25%。例如,如果 hz=1,则每次清理的最大时间为 250 毫秒;如果 hz=10,则每次清理的最大时间为 25 毫秒。

  3. 清理过程会依次遍历所有的数据库(db)。

  4. 在清理过程中,从每个数据库随机选择 20 个键,并判断它们是否过期。如果键过期,则会被删除。如果有超过 5 个键过期,会重新执行步骤 4;否则,会继续遍历下一个数据库。

  5. 在执行清理过程时,如果达到了 CPU 时间的 25%,就会退出清理过程。

清理内容的实现

Redis的清理过程,包括执行周期、过期键清理的时间限制、遍历数据库和随机选择键进行过期判断的步骤。同时,提及了在清理过程中限制 CPU 时间的机制,以保证不过度消耗 CPU 资源。这样有助于理解清理过程的工作原理并优化 Redis 的性能。

关于hz参数的一些讨论

调高hz参数可以提升清理的频率,过期key可以更及时的被删除,但hz太高会增加CPU时间的消耗;

代码分析如下:

void activeExpireCycle(int type) {.../* We can use at max ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC percentage of CPU time* per iteration. Since this function gets called with a frequency of* server.hz times per second, the following is the max amount of* microseconds we can spend in this function. */// 最多允许25%的CPU时间用于过期Key清理// 若hz=1,则一次activeExpireCycle最多只能执行250ms// 若hz=10,则一次activeExpireCycle最多只能执行25mstimelimit = 1000000*ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC/server.hz/100;...// 遍历所有dbfor (j = 0; j < dbs_per_call; j++) {int expired;redisDb *db = server.db+(current_db % server.dbnum);/* Increment the DB now so we are sure if we run out of time* in the current DB we'll restart from the next. This allows to* distribute the time evenly across DBs. */current_db++;/* Continue to expire if at the end of the cycle more than 25%* of the keys were expired. */do {...// 一次取20个Key,判断是否过期if (num > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP)num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP;while (num--) {dictEntry *de;long long ttl;if ((de = dictGetRandomKey(db->expires)) == NULL) break;ttl = dictGetSignedIntegerVal(de)-now;if (activeExpireCycleTryExpire(db,de,now)) expired++;}if ((iteration & 0xf) == 0) { /* check once every 16 iterations. */long long elapsed = ustime()-start;latencyAddSampleIfNeeded("expire-cycle",elapsed/1000);if (elapsed > timelimit) timelimit_exit = 1;}if (timelimit_exit) return;/* We don't repeat the cycle if there are less than 25% of keys* found expired in the current DB. */// 若有5个以上过期Key,则继续直至时间超过25%的CPU时间// 若没有5个过期Key,则跳过。} while (expired > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP/4);}
}

这是一个基于概率的简单算法,基本的假设是抽出的样本能够代表整个key空间,redis持续清理过期的数据直至将要过期的key的百分比降到了25%以下。这也意味着在长期来看任何给定的时刻已经过期但仍占据着内存空间的key的量最多为每秒的写操作量除以4.

由于算法采用的随机取key判断是否过期的方式,故几乎不可能清理完所有的过期Key;

Redis数据逐出策略

数据逐出时机
// 执行命令
int processCommand(redisClient *c) {.../* Handle the maxmemory directive.**First we try to free some memory if possible (if there are volatile* keys in the dataset). If there are not the only thing we can do* is returning an error. */if (server.maxmemory) {int retval = freeMemoryIfNeeded();...}...
}
数据逐出算法

在逐出算法中,根据用户设置的逐出策略,选出待逐出的key,直到当前内存小于最大内存值为主.

可选逐出策略如下:
  • volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
  • volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
  • volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据 淘汰
  • allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
  • allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
  • no-enviction(驱逐):禁止驱逐数据

具体代码如下

int freeMemoryIfNeeded() {...// 计算mem_usedmem_used = zmalloc_used_memory();.../* Check if we are over the memory limit. */if (mem_used <= server.maxmemory) return REDIS_OK;// 如果禁止逐出,返回错误if (server.maxmemory_policy == REDIS_MAXMEMORY_NO_EVICTION)return REDIS_ERR; /* We need to free memory, but policy forbids. */mem_freed = 0;mem_tofree = mem_used - server.maxmemory;long long start = ustime();latencyStartMonitor(latency);while (mem_freed < mem_tofree) {int j, k, keys_freed = 0;for (j = 0; j < server.dbnum; j++) {// 根据逐出策略的不同,选出待逐出的数据long bestval = 0; /* just to prevent warning */sds bestkey = NULL;struct dictEntry *de;redisDb *db = server.db+j;dict *dict;if (server.maxmemory_policy == REDIS_MAXMEMORY_ALLKEYS_LRU ||server.maxmemory_policy == REDIS_MAXMEMORY_ALLKEYS_RANDOM){dict = server.db[j].dict;} else {dict = server.db[j].expires;}if (dictSize(dict) == 0) continue;/* volatile-random and allkeys-random policy */if (server.maxmemory_policy == REDIS_MAXMEMORY_ALLKEYS_RANDOM ||server.maxmemory_policy == REDIS_MAXMEMORY_VOLATILE_RANDOM){de = dictGetRandomKey(dict);bestkey = dictGetKey(de);}/* volatile-lru and allkeys-lru policy */else if (server.maxmemory_policy == REDIS_MAXMEMORY_ALLKEYS_LRU ||server.maxmemory_policy == REDIS_MAXMEMORY_VOLATILE_LRU){for (k = 0; k < server.maxmemory_samples; k++) {sds thiskey;long thisval;robj *o;de = dictGetRandomKey(dict);thiskey = dictGetKey(de);/* When policy is volatile-lru we need an additional lookup* to locate the real key, as dict is set to db->expires.  **/if (server.maxmemory_policy == REDIS_MAXMEMORY_VOLATILE_LRU)de = dictFind(db->dict, thiskey);o = dictGetVal(de);thisval = estimateObjectIdleTime(o);/* Higher idle time is better candidate for deletion */if (bestkey == NULL || thisval > bestval) {bestkey = thiskey;bestval = thisval;}}}/* volatile-ttl */else if (server.maxmemory_policy == REDIS_MAXMEMORY_VOLATILE_TTL) {for (k = 0; k < server.maxmemory_samples; k++) {sds thiskey;long thisval;de = dictGetRandomKey(dict);thiskey = dictGetKey(de);thisval = (long) dictGetVal(de);/* Expire sooner (minor expire unix timestamp) is better* candidate for deletion **/if (bestkey == NULL || thisval < bestval) {bestkey = thiskey;bestval = thisval;}}}/* Finally remove the selected key. **/// 逐出挑选出的数据if (bestkey ) {...delta = (long long) zmalloc_used_memory();dbDelete(db,keyobj);delta -= (long long) zmalloc_used_memory();mem_freed += delta;...}}...}...return REDIS_OK;
}

总结归纳

  • 不要放垃圾数据,及时清理无用数据:定期清理垃圾数据和下线的业务数据,避免占用不必要的内存空间和资源。

  • 设置过期时间:对具有时效性的键设置合理的过期时间,利用Redis自身的过期键清理策略,降低过期键对内存的占用,并避免手动清理的麻烦。

  • 控制单个键的大小:避免单个键过大,防止网络传输延迟和内存资源消耗过多。通过业务拆分、数据压缩等方式,控制键的大小。

  • 使用不同逻辑数据库(db)分隔业务:在不同业务共享Redis时,最好使用不同的逻辑数据库进行分隔。这有助于过期键的及时清理,并方便问题排查和无用数据的下线。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/213994.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android View的 getHeight 和 getMeasuredHeight 的区别

前言 先简单复习一下Android View 的 绘制顺序&#xff1a; 1、onMeasure&#xff08;测量&#xff09;&#xff0c;先根据构造器传进来的LayoutParams&#xff08;布局参数&#xff09;&#xff0c;测量view宽高。 2、onLayout&#xff08;布局&#xff09;&#xff0c;再根…

ExoPlayer架构详解与源码分析(10)——H264Reader

系列文章目录 ExoPlayer架构详解与源码分析&#xff08;1&#xff09;——前言 ExoPlayer架构详解与源码分析&#xff08;2&#xff09;——Player ExoPlayer架构详解与源码分析&#xff08;3&#xff09;——Timeline ExoPlayer架构详解与源码分析&#xff08;4&#xff09;—…

iOS(swiftui)——系统悬浮窗( 可在其他应用上显示,可实时更新内容)

因为ios系统对权限的限制是比较严格的,ios系统本身是不支持全局悬浮窗(可在其他app上显示)。在iphone14及之后的iPhone机型中提供了一个叫 灵动岛的功能,可以在手机上方可以添加一个悬浮窗显示内容并实时更新,但这个功能有很多局限性 如:需要iPhone14及之后的机型且系统…

软件测试相关

软件测试是什么&#xff1f; 使用人工和自动手段来运行或测试某个系统的过程&#xff0c;其目的在于验证它是否满足规定的需求或弄清预期结果与实际结果的差别。 为什么做软件测试&#xff1f;目的是什么&#xff1f; 发现软件存在的代码或业务逻辑错误 检验产品是否符合用户需…

基于Lucene的全文检索系统的实现与应用

文章目录 一、概念二、引入案例1、数据库搜索2、数据分类3、非结构化数据查询方法1&#xff09; 顺序扫描法(Serial Scanning)2&#xff09;全文检索(Full-text Search) 4、如何实现全文检索 三、Lucene实现全文检索的流程1、索引和搜索流程图2、创建索引1&#xff09;获取原始…

掌控安全 暖冬杯 CTF Writeup By AheadSec

本来结束时发到了学校AheadSec的群里面了的&#xff0c;觉得这比赛没啥好外发WP的&#xff0c;但是有些师傅来问了&#xff0c;所以还是发一下吧。 文章目录 Web签到&#xff1a;又一个计算题计算器PHP反序列化又一个PHP反序列化 Misc这是邹节伦的桌面背景图什么鬼&#xff1f;…

Dockerfile部署Java项目挂载使用外部配置文件

Dockerfile部署Java项目挂载使用外部配置文件 技术博客 http://idea.coderyj.com/ 需求是由于java项目使用的是nacos 而且每次部署nacos服务器ip不一样导致要重新打包,想引入外部配置文件进行打包 1.需求是由于java项目使用的是nacos 而且每次部署nacos服务器ip不一样导致要重新…

B 站基于 StarRocks 构建大数据元仓

作者&#xff1a;bilibili 大数据高级开发工程师 杨洋 B站大数据元仓是一款用来观测大数据引擎运行情况、推动大作业治理的系统诊断产品。经过调研和性能测试&#xff0c;大数据元仓最终以 StarRocks 为技术底座&#xff0c;从实际的应用效果来看&#xff0c;大部分查询都能在几…

【VS Code】Visual Studio Code 你必须安装的 Plugins - 持续更新

文章目录 GitLens — Git supercharged【真香】EditorConfig for VS Code【真香】Remote - SSH【真香】MySQL【真香】 Talk is cheap, show me the code. GitLens — Git supercharged【真香】 插件地址&#xff1a; https://marketplace.visualstudio.com/items?itemNameeam…

5G - NR物理层解决方案支持6G非地面网络中的高移动性

文章目录 非地面网络场景链路仿真参数实验仿真结果 非地面网络场景 链路仿真参数 实验仿真结果 Figure 5 && Figure 6&#xff1a;不同信噪比下的BER和吞吐量 变量 SISO 2x2MIMO 2x4MIMO 2x8MIMOReyleigh衰落、Rician衰落、多径TDL-A(NLOS) 、TDL-E(LOS)(a)QPSK (b)16…

cache教程 3.HTTP服务器

上一节我们实现了单机版的缓存服务&#xff0c;但是我们的目标是分布式缓存。那么&#xff0c;我们就需要把缓存服务部署到多态机器节点上&#xff0c;对外提供访问接口。客户端就可以通过这些接口去实现缓存的增删改查。 分布式缓存需要实现节点间通信&#xff0c;而通信方法…

【ArcGIS Pro微课1000例】0049:根据坐标快速定位(创建点位)的常见方法

文章目录 一、转到XY1. 闪烁位置2. 平移3. 标记位置二、定位1. 坐标定位2. 添加到图形3. 添加至要素类三、添加XY坐标四、创建点要素一、转到XY 举例:经纬度坐标:113.2583286东, 23.1492340北 。 1. 闪烁位置 输入坐标,点击闪烁位置工具,即可在对应的位置出现一个绿色闪烁…

Bash脚本处理ogg、flac格式到mp3格式的批量转换

现在下载的许多音乐文件是flac和ogg格式的&#xff0c;QQ音乐上下载的就是这样的&#xff0c;这些文件尺寸比较大&#xff0c;在某些场合使用不便&#xff0c;比如在车机上播放还是mp3格式合适&#xff0c;音质这些在车机上播放足够了&#xff0c;要求不高。比如本人就喜欢下载…

西南科技大学C++程序设计实验十(函数模板与类模板)

一、实验目的 1. 掌握函数模板与类模板; 2. 掌握数组类、链表类等线性群体数据类型定义与使用; 二、实验任务 1. 分析完善以下程序,理解模板类的使用: (1)补充类模板声明语句。 (2)创建不同类型的类对象,使用时明确其数据类型? _template<typename T>__…

最简单的基于 FFmpeg 的音频解码器

最简单的基于 FFmpeg 的音频解码器 最简单的基于 FFmpeg 的音频解码器正文参考工程文件下载 参考雷霄骅博士的文章&#xff0c;链接&#xff1a;最简单的基于FFMPEGSDL的音频播放器&#xff1a;拆分-解码器和播放器 最简单的基于 FFmpeg 的音频解码器 正文 FFmpeg 音频解码器…

『 MySQL数据库 』聚合统计

文章目录 前言 &#x1f951;&#x1f95d; 聚合函数&#x1f353; COUNT( ) 查询数据数量&#x1f353; SUM( ) 查询数据总和&#x1f353; AVG( ) 查询数据平均值&#x1f353; MAX( ) 查询数据最大值&#x1f353; MIN( ) 查询数据最小值 &#x1f95d; 数据分组GROUP BY子句…

Rellax.js,一款超酷的 JavaScript 滚动效果库

嗨&#xff0c;大家好&#xff0c;欢迎来到猿镇&#xff0c;我是镇长&#xff0c;lee。 又到了和大家见面的时间&#xff0c;今天和大家分享一款轻松实现视差滚动效果的 JavaScript 库——Rellax.js。无需大量的配置&#xff0c;即可为你的网站增色不少。 什么是Rellax.js&am…

LabVIEW发开发电状态监测系统

LabVIEW发开发电状态监测系统 对发电设备的持续监测对于确保可靠的电力供应至消费者极为重要。它不仅能够及时提醒操作员注意发电设备的潜在损坏&#xff0c;还能减少由于设备故障造成的停机时间。为了达到这一目标&#xff0c;开发了一款基于LabVIEW的软件&#xff0c;专门用…

TypeScript基本语法

想在自己电脑上快速演示下方代码&#xff1f;点击ts官方演练场&#xff1a;https://www.typescriptlang.org/play 变量声明&#xff1a;TypeScript 在 Javascript的基础上加入了静态类型检查功能&#xff0c;因此每一个变量都有固定的数据类型。 //string: 字符串&#xff0c;…

使用Rust 构建C 组件

协议解析&#xff0c;这不就很快了&#xff0c;而且原生的标准库红黑树和avl 树支持&#xff0c;异步tokio 这些库&#xff0c;编写应用组件就很快了 rust 标准库不支持 unix 的消息队列&#xff0c;但是支持 shm 和 uds&#xff0c;后者从多方面考虑都比&#xff0c;消息队列更…