积极向上 https://www.keyboard-man.com/ Recent content on 积极向上 Hugo zh-CN Mon, 23 Mar 2026 15:00:00 +0800 用大模型打造个人翻译工具:100行代码的智能助手 https://www.keyboard-man.com/post/using-llm-to-build-translator/ Mon, 23 Mar 2026 15:00:00 +0800 https://www.keyboard-man.com/post/using-llm-to-build-translator/ <p>日常工作中经常需要阅读英文文档、写代码注释、或者和外国同事沟通。虽然市面上有很多翻译工具,但总觉得不够顺手:</p> <ul> <li>浏览器插件:需要打开浏览器,有时候只想在终端里快速翻译</li> <li>在线翻译网站:需要切换窗口,打断工作流</li> <li>商业翻译 API:按字符收费,对于日常使用来说有点贵</li> </ul> <p>于是我想:<strong>能不能用大模型 API 做一个简单的命令行翻译工具?</strong></p> 游戏服务端消息队列设计与实现 https://www.keyboard-man.com/post/game-server-message-queue/ Mon, 23 Mar 2026 01:55:00 +0800 https://www.keyboard-man.com/post/game-server-message-queue/ <p>在游戏服务端开发中,消息队列是 Actor 模型的核心组件。本文介绍 kapi 框架中消息队列的设计与实现,包括双缓冲设计、overload 保护机制,以及线程安全的考量。</p> Boost.Asio 网络库用法与压力测试 https://www.keyboard-man.com/post/boost-asio-usage-and-benchmark/ Mon, 23 Mar 2026 01:30:00 +0800 https://www.keyboard-man.com/post/boost-asio-usage-and-benchmark/ <p>Boost.Asio 是一个高性能的 C++ 网络编程库,广泛应用于各种网络服务开发。本文将介绍 Asio 的几种典型用法,并演示如何进行压力测试。</p> 解决数据竞争-Valgrind https://www.keyboard-man.com/post/valgrind_data_race/ Wed, 08 Jan 2025 17:19:05 +0800 https://www.keyboard-man.com/post/valgrind_data_race/ <h4 id="一背景">一、背景</h4> <p>数据竞争在多线程编程中容易出现且难以察觉,尤其是项目复杂变量变多之后。靠人力阅读代码心智负担太大,这时候引入<strong>valgrind</strong>工具就可以帮我们很容易发现数据竞争从而解决问题。</p> skynet伪并发 https://www.keyboard-man.com/post/skynet_pseudo_concurrent/ Thu, 27 Oct 2022 11:08:40 +0800 https://www.keyboard-man.com/post/skynet_pseudo_concurrent/ <h4 id="一背景">一、背景</h4> <p><strong>和 erlang 不同,一个 skynet 服务在某个业务流程被挂起后,即使回应消息尚未收到,它还是可以处理其他的消息的。所以同一个 skynet 服务可以同时拥有多条业务执行线。所以,你尽可以让同一个 skynet 服务处理很多消息,它们会看起来并行,和真正分拆到不同的服务中处理的区别是,这些处理流程永远不会真正的并行,它们只是在轮流工作。一段业务会一直运行到下一个 IO 阻塞点,然后切换到下一段逻辑。你可以利用这一点,让多条业务线在处理时共享同一组数据,这些数据在同一个 lua 虚拟机下时,读写起来都比通过消息交换要廉价的多。</strong></p> skynet火焰图 https://www.keyboard-man.com/post/skynet_profile/ Wed, 26 Oct 2022 18:05:37 +0800 https://www.keyboard-man.com/post/skynet_profile/ <h4 id="一背景">一、背景</h4> <p>前面<a href="../wgame_group/">腾讯云mongo服务采坑</a>和<a href="../mongo_cpu/">优化Mongo降CPU</a>两篇文章从两个角度记录了我们解决水晶活动异常所用到的方式。但这些都是外部的,真正是否机器不够用、数据库拖慢服务还是其它问题还是得从代码层面入手。从数据库入库记录和请求日志已经很清晰就是水晶抽卡导致负载上升服务异常的,所以直接压测接口找到代码层面问题是最首先应该做的事,而火焰图就是最好的工具。</p> 优化Mongo降CPU https://www.keyboard-man.com/post/mongo_cpu/ Wed, 26 Oct 2022 10:02:38 +0800 https://www.keyboard-man.com/post/mongo_cpu/ <h4 id="一背景">一、背景</h4> <p>前面<a href="../wgame_group/">腾讯云mongo服务采坑</a>中提到每次水晶活动才开始的时候会吸引大量玩家来抽卡,会导致cpu居高。当然就算没有水晶活动每日凌晨跨天游戏玩法重置等入库外加新的一天较多玩家同时进入也会导致cpu比平时多挺多,如图所示。 <img class="mx-auto" alt="tencent-mongo-cpu-0916" src="https://storage.keyboard-man.com/site-web/images/tencent-mongo-cpu-0916.png" /> </p> <h4 id="二降cpu">二、降CPU</h4> <h5 id="加机器">加机器</h5> <p>避免单实例cpu太高的方法也可以通过加机器(增加mongo服务实例)来解决,但是已经在当前实例的数据库迁移到新实例的话需要关服以及处理一些配置,这不是我们想要的。</p> <h5 id="加索引">加索引</h5> <p>如果更新mongo的集合不是以<code>_id</code>为筛选条件的话,大多时候都需要增加对应的索引,避免更新时遍历全表。事实上我们基本每个表在上线前都已经加上了索引,查看慢查询补上遗漏的几张表的索引后有少许好点,但问题依然很严重。</p> 腾讯云mongo服务采坑 https://www.keyboard-man.com/post/wgame_group/ Tue, 25 Oct 2022 16:54:27 +0800 https://www.keyboard-man.com/post/wgame_group/ <h4 id="一背景">一、背景</h4> <p>我们项目存储游戏数据采用的mongo服务,流水等记录数据存储采用的mysql服务。之前是部署到每台业务机器上,开在线上机器的游戏服一般直接连接本机mongo服务。最新的项目由于业务增长运营方要求将我们使用的mongo服务和mysql服务迁移到腾讯的云服务上面去,保障”<strong>数据库的安全可用</strong>“。</p> 后端服务动态转发 https://www.keyboard-man.com/post/dynamic-redirect/ Tue, 25 Oct 2022 16:01:34 +0800 https://www.keyboard-man.com/post/dynamic-redirect/ <h4 id="一背景">一、背景</h4> <p>当前我们游戏架构通过水平扩展wgame节点(和区服无关只处理玩家连接和玩家服务数据)来承载在线玩家的。通过一直扩展减轻单个wgame节点负载和承载更多在线玩家。</p> <p>在wgame节点前面增加一层nginx以实现wss(客户端和服务端通过websocket连接,但是微信等小程序要求wss)。以前单个渠道不用太多wgame节点就能满足线上需求,随着业务增长和游戏类型决定同时在线玩家数较以前出现较大增长,每次增加线上新机器或者机器上面新增wgame节点(wgame监听客户端连接端口)就需要重新生成nginx配置并reload一次,导致nginx配置越来越难维护。后期统一入口即在nginx前面加入SLB之后每次还需要在SLB增加新的端口监听和转发。</p> etcd lualib for skynet https://www.keyboard-man.com/post/etcd-service/ Mon, 24 Oct 2022 18:30:00 +0800 https://www.keyboard-man.com/post/etcd-service/ <h4 id="一背景">一、背景</h4> <p>以前项目配置都是放在skynet的启动配置里面,当线上项目进程节点变多后需要加新配置内容的时候需要全部重新生成启动配置,不统一的配置内容(mongo数据库地址、mysql数据库地址、进程节点ip和进程监听端口等)会导致配置管理变得非常麻烦,而且不能比较方便实时更改配置。为了解决这个问题我们引入<a href="https://github.com/etcd-io/etcd">etcd</a>来管理所有业务配置,现在skynet启动配置只需要传入etcd所需要必要参数即可。现在的配置内容大体示例为:</p> 一条SQL查询语句是如何执行的 MySQL学习笔记 一 https://www.keyboard-man.com/post/how-query-statement-execution/ Thu, 17 Feb 2022 20:25:11 +0800 https://www.keyboard-man.com/post/how-query-statement-execution/ <p>大体来说MySQL可以分为Server层和存储引擎层两部分。 Server层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖MySQL的大多数核心服务功能,以及所有的内置函数(日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。 存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持InnoDB、MyISAM、Memory等多个存储引擎。现在最常用的存储引擎是InnoDB,从MySQL5.5.5版本开始成为了默认存储引擎。</p> Redis String https://www.keyboard-man.com/post/redis-string/ Mon, 02 Aug 2021 22:42:59 +0800 https://www.keyboard-man.com/post/redis-string/ <p>一、数据结构基础</p> <ol> <li>sds在C字符数组的基础上增加了长度和空间元数据,使基于字符串长度的追加、复制、比较等操作可以直接读取元数据,提升效率。。</li> <li>SDS总共设计了五种类型,分别为sdshdr5、sdshdr8、sdshdr16、sdshdr32和sdshdr64。他们的主要区别是数据结构中字符数组现有len和分配空间长度alloc的不同,sdshdr5没有被使用,后四种len数据类型分别为uint8_t、uint16_t、uint32_t、uint64_t。</li> </ol> <pre tabindex="0"><code>struct __attribute__ ((__packed__)) sdshdr8 { uint8_t len; /* used */ uint8_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ char buf[]; }; struct __attribute__ ((__packed__)) sdshdr64 { uint64_t len; /* used */ uint64_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ char buf[]; }; </code></pre><ol start="3"> <li>SDS设计不同的结构头是为了灵活保存不同大小的字符串,从而有效节省空间。结构头占用内存空间不一样,保存小字符串时结构头占用小可以节约内存。</li> <li>结构体定义中<code>__attribute__ ((__packed__))</code>的作用是告诉编译器不要使用字节对齐方式,而是采用紧凑型额方式分配内存(默认情况编译器会按照8字节对齐的方式分配内存)。</li> <li>为了避免频繁内存重新分配,当SDS扩容时,如果所需内存小于1M时扩容翻倍,当大于等于1M时扩大1M。</li> <li>SDS保存数据的末尾设置为空字符,并且总会为buf数组分配空间时多分配一个字节来容纳这个空字符,使保存文本数据的SDS可以重用一部分&lt;string.h&gt;库定义的函数。</li> <li>SDS采用惰性空间的释放策略。</li> </ol> <p>二、C字符串与SDS比较</p> Redis Hash https://www.keyboard-man.com/post/redis-hash/ Mon, 02 Aug 2021 10:58:22 +0800 https://www.keyboard-man.com/post/redis-hash/ <ol> <li>Redis中的dict数据结构采用<strong>链式哈希</strong>方式存储。负载因子大于等于1时触发哈希扩容检测,当存在RDB子进程或者AOF子进程时关闭哈希扩容(避免父进程大量写时复制),不过即使没开启hash扩容在负载因子大于<strong>dict_force_resize_ratio</strong>时也会执行哈希扩容,扩容大小为当前容量的2倍。</li> <li>当往Redis中写入新的键值对或者是修改键值对时,Redis都会判断是否需要rehash,函数调用链为:dictAdd/dictReplace/dictAddOrFind -&gt; dictAddRaw -&gt; _dictKeyIndex -&gt; _dictExpandIfNeeded。</li> <li>Redis哈希扩容时使用渐进式rehash,即每次只进行n个bucket的rehash处理,避免大量的键需要从原来的位置拷贝到新位置时主线程无法执行其他请求而阻塞;rehash时当出现10*n个都为空bucket时会结束本次处理,防止阻塞太长时间。</li> <li>Redis中有五处函数调用_dictRehashStep进而调用dictRehash函数来执行rehash,调用链为:ictAddRow/dictGenericDelete/dictFind/dictGetRandomKey/dictGetSomeKeys -&gt; _dictRehashStep -&gt; dictRehash。</li> <li>全局哈希表除了主动函数调用(增删改查)执行rehash外还有定时rehash,主线程会默认每间隔100ms执行一次迁移操作。单次以100bucket作为单位迁移数据,如果超过1ms就结束当前迁移。</li> <li>在rehash期间,查询hash表找不到结果时还会在新哈希表查询一次。</li> </ol> Redis核心技术与实战 学习笔记 一 https://www.keyboard-man.com/post/2021-01-20-redis-core-technology-learning-notes-one/ Wed, 20 Jan 2021 19:51:22 +0800 https://www.keyboard-man.com/post/2021-01-20-redis-core-technology-learning-notes-one/ <p>Redis的特性是“快”。一方面是因为它是内存数据库,所有操作都在内存上完成,内存的访问速度本身就很快。另一方面归功于它的数据结构。键值对是按一定的数据结构来组织的,操作键值对最终就是对数据结构进行增删改查操作,所以高效的数据结构是Redis快速处理的基础。</p> 程序员修炼之道 读书笔记 一 https://www.keyboard-man.com/post/2021-01-18-the-pragmatic-programmer/ Mon, 18 Jan 2021 22:47:22 +0800 https://www.keyboard-man.com/post/2021-01-18-the-pragmatic-programmer/ <p>很喜欢书中序言对编程作出的解释;编程关涉诸事&ndash;尽量减少未来的痛苦,让队友更轻松,做错事情后能够重新振作起来,养成良好的习惯,以及理解工具集。</p> keyboard-man.com https://www.keyboard-man.com/post/2021-01-14-keyboard-man/ Thu, 14 Jan 2021 23:21:07 +0800 https://www.keyboard-man.com/post/2021-01-14-keyboard-man/ <p>Welcome to here.</p> <p>This is not all, the more things are coming in the world !</p> 关于我 https://www.keyboard-man.com/about/ Thu, 14 Jan 2021 23:21:07 +0800 https://www.keyboard-man.com/about/ <p>This is not all, the more things are coming in the world !</p>