 2.游戏战中陪伴助手微服务架构设计与应用初始方案——Lua 方案 显而易见的问题 范畴 问题 需求 - 所有策略需求都需要走开发流程 - 迭代周期长:2周开发、测试、上线 运营 - 变更困难,修改策略 = 修改代码 开发 - 代码低内聚,交接难度大 扩展 - 没有考虑扩展 功能 - 难以实现战略推荐 - 早期:先考虑有无 - 引入推荐系统 系统思考——如何评判方案的好坏? 需要定义几个维度来评判一个方案的好坏 - 响应性能: 左:配置文件 - 右:大数据挖掘 - 不足: - 太 bug 了,限制使用 方案探索——聚类统计 模仿大多数玩家的选择 - 实现方法: - 为玩家生成 [0, 1] 特征向量 - 聚类统计,存入 Faiss - 实时 Faiss 匹配召回 - 问题: - 特征过多(600多维),无法分析 - 聚类结果趋同 方案探索——关键帧 / 路径推荐 模仿某一个玩家的选择 - 专利:《一 推荐系统:策略召回和推荐 - 数据分析:离线策略挖掘和模型训练 - 管理平台:开发、运营、运维辅助 实现方案——Token 清洗 Token 清洗服务完整流程 - 挑战:150+类 token,如何高内聚,降低 token 计算逻辑复杂度 - 方案:Token 计算插件化 - 技术选型: - 对比:Lua vs Go 二进制——开发灵活 vs 性能 - 思考:Go 脚本? - 最终方案: -0 码力 | 47 页 | 11.10 MB | 1 年前3 2.游戏战中陪伴助手微服务架构设计与应用初始方案——Lua 方案 显而易见的问题 范畴 问题 需求 - 所有策略需求都需要走开发流程 - 迭代周期长:2周开发、测试、上线 运营 - 变更困难,修改策略 = 修改代码 开发 - 代码低内聚,交接难度大 扩展 - 没有考虑扩展 功能 - 难以实现战略推荐 - 早期:先考虑有无 - 引入推荐系统 系统思考——如何评判方案的好坏? 需要定义几个维度来评判一个方案的好坏 - 响应性能: 左:配置文件 - 右:大数据挖掘 - 不足: - 太 bug 了,限制使用 方案探索——聚类统计 模仿大多数玩家的选择 - 实现方法: - 为玩家生成 [0, 1] 特征向量 - 聚类统计,存入 Faiss - 实时 Faiss 匹配召回 - 问题: - 特征过多(600多维),无法分析 - 聚类结果趋同 方案探索——关键帧 / 路径推荐 模仿某一个玩家的选择 - 专利:《一 推荐系统:策略召回和推荐 - 数据分析:离线策略挖掘和模型训练 - 管理平台:开发、运营、运维辅助 实现方案——Token 清洗 Token 清洗服务完整流程 - 挑战:150+类 token,如何高内聚,降低 token 计算逻辑复杂度 - 方案:Token 计算插件化 - 技术选型: - 对比:Lua vs Go 二进制——开发灵活 vs 性能 - 思考:Go 脚本? - 最终方案: -0 码力 | 47 页 | 11.10 MB | 1 年前3
 2.2.5 Go 如何助力企业进行微服务转型数据拆分 • 数据不能乱,规则先确定 • 定义数据边界,避免数据冗余 • 数据库互相隔离,避免故障传递 • No join, no pain! ⽤户 商品 订单 物流 接⼝聚类收敛 • 按功能聚类接⼝ • 避免微服务过微 • 避免调⽤链路过深 正确性验证 • 循序渐进可回滚 • fork请求,验证返回 • 灰度逐步迁移 • 监控有⽆漏⽹请求 • 保留回滚可能性0 码力 | 25 页 | 4.51 MB | 1 年前3 2.2.5 Go 如何助力企业进行微服务转型数据拆分 • 数据不能乱,规则先确定 • 定义数据边界,避免数据冗余 • 数据库互相隔离,避免故障传递 • No join, no pain! ⽤户 商品 订单 物流 接⼝聚类收敛 • 按功能聚类接⼝ • 避免微服务过微 • 避免调⽤链路过深 正确性验证 • 循序渐进可回滚 • fork请求,验证返回 • 灰度逐步迁移 • 监控有⽆漏⽹请求 • 保留回滚可能性0 码力 | 25 页 | 4.51 MB | 1 年前3
 1.2 基于 Golang 构建高可扩展的云原生 PaaS 平台- 不仅是web框架 - 不仅是微服务框架 - 为扩展⽽⽣ - 以模块化的开发为核⼼ VS 模块化开发原则 - ⾯向接⼝进⾏开发,⽽不是⾯向实现 - 模块拆分的粒度尽可能⼩ - 模块内聚,模块间松耦合 - 模块间的引⽤使⽤DI⽽不是直接依赖实现包 - 服务可以由多个模块拼装组成 ⼀个最简单的模块定义 - 可以使⽤ cli ⽣成模块 template - 模块需要主动在config0 码力 | 40 页 | 8.60 MB | 1 年前3 1.2 基于 Golang 构建高可扩展的云原生 PaaS 平台- 不仅是web框架 - 不仅是微服务框架 - 为扩展⽽⽣ - 以模块化的开发为核⼼ VS 模块化开发原则 - ⾯向接⼝进⾏开发,⽽不是⾯向实现 - 模块拆分的粒度尽可能⼩ - 模块内聚,模块间松耦合 - 模块间的引⽤使⽤DI⽽不是直接依赖实现包 - 服务可以由多个模块拼装组成 ⼀个最简单的模块定义 - 可以使⽤ cli ⽣成模块 template - 模块需要主动在config0 码力 | 40 页 | 8.60 MB | 1 年前3
 1.5 Go 语言构建高并发分布式系统实践所有实例组通信数据监控 性能监控与调优 架构迭代 压测平台 拆分多实例 l 缓解GC压⼒力(gc时间减少40%) 按业务类型聚类,⼲⼴广播(io密集),多播,点对点(内部通信密集),聊天室(cpu密集) 分层服务,按层次扩展改为分集群(Set/Cell思想),各⾃自独⽴立,⼜又具备全被全部功能⼦子集群 l 按业务拆分(助⼿手,卫⼠士,浏览器)0 码力 | 39 页 | 5.23 MB | 1 年前3 1.5 Go 语言构建高并发分布式系统实践所有实例组通信数据监控 性能监控与调优 架构迭代 压测平台 拆分多实例 l 缓解GC压⼒力(gc时间减少40%) 按业务类型聚类,⼲⼴广播(io密集),多播,点对点(内部通信密集),聊天室(cpu密集) 分层服务,按层次扩展改为分集群(Set/Cell思想),各⾃自独⽴立,⼜又具备全被全部功能⼦子集群 l 按业务拆分(助⼿手,卫⼠士,浏览器)0 码力 | 39 页 | 5.23 MB | 1 年前3
 Go vs. GoPlus(Go+)error processing return } defer f.Close() ... // process file data 惊喜6:功能内聚 • 用组合实现继承(包括虚拟继承) type Foo struct { // 继承 Base ... } type Foo struct { // 虚拟继承0 码力 | 54 页 | 1.82 MB | 1 年前3 Go vs. GoPlus(Go+)error processing return } defer f.Close() ... // process file data 惊喜6:功能内聚 • 用组合实现继承(包括虚拟继承) type Foo struct { // 继承 Base ... } type Foo struct { // 虚拟继承0 码力 | 54 页 | 1.82 MB | 1 年前3
 Hello 算法 1.2.0 繁体中文 Go 版叫自身來解決問題。它主要包含兩個階段。 1. 遞:程式不斷深入地呼叫自身,通常傳入更小或更簡化的參數,直到達到“終止條件”。 2. 迴:觸發“終止條件”後,程式從最深層的遞迴函式開始逐層返回,匯聚每一層的結果。 而從實現的角度看,遞迴程式碼主要包含三個要素。 1. 終止條件:用於決定什麼時候由“遞”轉“迴”。 2. 遞迴呼叫:對應“遞”,函式呼叫自身,通常輸入更小或更簡化的參數。 3. 。 圖 6‑6 開放定址(線性探查)雜湊表的鍵值對分佈 然而,線性探查容易產生“聚集現象”。具體來說,陣列中連續被佔用的位置越長,這些連續位置發生雜湊衝 突的可能性越大,從而進一步促使該位置的聚堆積生長,形成惡性迴圈,最終導致增刪查改操作效率劣化。 值得注意的是,我們不能在開放定址雜湊表中直接刪除元素。這是因為刪除元素會在陣列內產生一個空桶 None ,而當查詢元素時,線性探查到該空桶就 0, 3, 6, 0, 3, 6, 0, 3, 6, … } 第 6 章 雜湊表 www.hello‑algo.com 131 如果輸入 key 恰好滿足這種等差數列的資料分佈,那麼雜湊值就會出現聚堆積,從而加重雜湊衝突。現在, 假設將 modulus 替換為質數 13 ,由於 key 和 modulus 之間不存在公約數,因此輸出的雜湊值的均勻性會明 顯提升。 modulus = 130 码力 | 385 页 | 18.80 MB | 10 月前3 Hello 算法 1.2.0 繁体中文 Go 版叫自身來解決問題。它主要包含兩個階段。 1. 遞:程式不斷深入地呼叫自身,通常傳入更小或更簡化的參數,直到達到“終止條件”。 2. 迴:觸發“終止條件”後,程式從最深層的遞迴函式開始逐層返回,匯聚每一層的結果。 而從實現的角度看,遞迴程式碼主要包含三個要素。 1. 終止條件:用於決定什麼時候由“遞”轉“迴”。 2. 遞迴呼叫:對應“遞”,函式呼叫自身,通常輸入更小或更簡化的參數。 3. 。 圖 6‑6 開放定址(線性探查)雜湊表的鍵值對分佈 然而,線性探查容易產生“聚集現象”。具體來說,陣列中連續被佔用的位置越長,這些連續位置發生雜湊衝 突的可能性越大,從而進一步促使該位置的聚堆積生長,形成惡性迴圈,最終導致增刪查改操作效率劣化。 值得注意的是,我們不能在開放定址雜湊表中直接刪除元素。這是因為刪除元素會在陣列內產生一個空桶 None ,而當查詢元素時,線性探查到該空桶就 0, 3, 6, 0, 3, 6, 0, 3, 6, … } 第 6 章 雜湊表 www.hello‑algo.com 131 如果輸入 key 恰好滿足這種等差數列的資料分佈,那麼雜湊值就會出現聚堆積,從而加重雜湊衝突。現在, 假設將 modulus 替換為質數 13 ,由於 key 和 modulus 之間不存在公約數,因此輸出的雜湊值的均勻性會明 顯提升。 modulus = 130 码力 | 385 页 | 18.80 MB | 10 月前3
 Hello 算法 1.0.0b4 Golang版时,该空位可能导致 程序误判元素不存在。为此,通常需要借助一个标志位来标记已删除元素。 ‧ 容易产生聚集。数组内连续被占用位置越长,这些连续位置发生哈希冲突的可能性越大,进一步促使这 一位置的聚堆生长,形成恶性循环,最终导致增删查改操作效率劣化。 以下代码实现了一个简单的开放寻址(线性探测)哈希表。值得注意两点: 6. 散列表 hello‑algo.com 102 ‧ 我们使用一个固定的键值对实例 27, 30, 33, ⋯} hash = {0, 3, 6, 0, 3, 6, 0, 3, 6, 0, 3, 6, ⋯} 如果输入 key 恰好满足这种等差数列的数据分布,那么哈希值就会出现聚堆,从而加重哈希冲突。现在,假设 将 modulus 替换为质数 13 ,由于 key 和 modulus 之间不存在公约数,输出的哈希值的均匀性会明显提升。 modulus = 13 key = 冲突元素存储在同一个链表中。然而,链表过长会降低查 询效率,可以进一步将链表转换为红黑树来提高效率。 ‧ 开放寻址通过多次探测来处理哈希冲突。线性探测使用固定步长,缺点是不能删除元素,且容易产生聚 集。多次哈希使用多个哈希函数进行探测,相较线性探测更不易产生聚集,但多个哈希函数增加了计算 量。 ‧ 不同编程语言采取了不同的哈希表实现。例如,Java 的 HashMap 使用链式地址,而 Python0 码力 | 347 页 | 27.40 MB | 1 年前3 Hello 算法 1.0.0b4 Golang版时,该空位可能导致 程序误判元素不存在。为此,通常需要借助一个标志位来标记已删除元素。 ‧ 容易产生聚集。数组内连续被占用位置越长,这些连续位置发生哈希冲突的可能性越大,进一步促使这 一位置的聚堆生长,形成恶性循环,最终导致增删查改操作效率劣化。 以下代码实现了一个简单的开放寻址(线性探测)哈希表。值得注意两点: 6. 散列表 hello‑algo.com 102 ‧ 我们使用一个固定的键值对实例 27, 30, 33, ⋯} hash = {0, 3, 6, 0, 3, 6, 0, 3, 6, 0, 3, 6, ⋯} 如果输入 key 恰好满足这种等差数列的数据分布,那么哈希值就会出现聚堆,从而加重哈希冲突。现在,假设 将 modulus 替换为质数 13 ,由于 key 和 modulus 之间不存在公约数,输出的哈希值的均匀性会明显提升。 modulus = 13 key = 冲突元素存储在同一个链表中。然而,链表过长会降低查 询效率,可以进一步将链表转换为红黑树来提高效率。 ‧ 开放寻址通过多次探测来处理哈希冲突。线性探测使用固定步长,缺点是不能删除元素,且容易产生聚 集。多次哈希使用多个哈希函数进行探测,相较线性探测更不易产生聚集,但多个哈希函数增加了计算 量。 ‧ 不同编程语言采取了不同的哈希表实现。例如,Java 的 HashMap 使用链式地址,而 Python0 码力 | 347 页 | 27.40 MB | 1 年前3
 Hello 算法 1.1.0 Go版。 图 6‑6 开放寻址(线性探测)哈希表的键值对分布 然而,线性探测容易产生“聚集现象”。具体来说,数组中连续被占用的位置越长,这些连续位置发生哈希冲 突的可能性越大,从而进一步促使该位置的聚堆生长,形成恶性循环,最终导致增删查改操作效率劣化。 值得注意的是,我们不能在开放寻址哈希表中直接删除元素。这是因为删除元素会在数组内产生一个空桶 None ,而当查询元素时,线性探测到该空桶就会 6, 0, 3, 6, 0, 3, 6, 0, 3, 6, … } 第 6 章 哈希表 hello‑algo.com 131 如果输入 key 恰好满足这种等差数列的数据分布,那么哈希值就会出现聚堆,从而加重哈希冲突。现在,假 设将 modulus 替换为质数 13 ,由于 key 和 modulus 之间不存在公约数,因此输出的哈希值的均匀性会明显 提升。 modulus = 13 key 元素存储在同一个链表中。然而,链表过长会降低查 询效率,可以通过进一步将链表转换为红黑树来提高效率。 ‧ 开放寻址通过多次探测来处理哈希冲突。线性探测使用固定步长,缺点是不能删除元素,且容易产生聚 集。多次哈希使用多个哈希函数进行探测,相较线性探测更不易产生聚集,但多个哈希函数增加了计算 量。 ‧ 不同编程语言采取了不同的哈希表实现。例如,Java 的 HashMap 使用链式地址,而 Python0 码力 | 383 页 | 18.48 MB | 1 年前3 Hello 算法 1.1.0 Go版。 图 6‑6 开放寻址(线性探测)哈希表的键值对分布 然而,线性探测容易产生“聚集现象”。具体来说,数组中连续被占用的位置越长,这些连续位置发生哈希冲 突的可能性越大,从而进一步促使该位置的聚堆生长,形成恶性循环,最终导致增删查改操作效率劣化。 值得注意的是,我们不能在开放寻址哈希表中直接删除元素。这是因为删除元素会在数组内产生一个空桶 None ,而当查询元素时,线性探测到该空桶就会 6, 0, 3, 6, 0, 3, 6, 0, 3, 6, … } 第 6 章 哈希表 hello‑algo.com 131 如果输入 key 恰好满足这种等差数列的数据分布,那么哈希值就会出现聚堆,从而加重哈希冲突。现在,假 设将 modulus 替换为质数 13 ,由于 key 和 modulus 之间不存在公约数,因此输出的哈希值的均匀性会明显 提升。 modulus = 13 key 元素存储在同一个链表中。然而,链表过长会降低查 询效率,可以通过进一步将链表转换为红黑树来提高效率。 ‧ 开放寻址通过多次探测来处理哈希冲突。线性探测使用固定步长,缺点是不能删除元素,且容易产生聚 集。多次哈希使用多个哈希函数进行探测,相较线性探测更不易产生聚集,但多个哈希函数增加了计算 量。 ‧ 不同编程语言采取了不同的哈希表实现。例如,Java 的 HashMap 使用链式地址,而 Python0 码力 | 383 页 | 18.48 MB | 1 年前3
 Hello 算法 1.0.0 Golang版。 图 6‑6 开放寻址(线性探测)哈希表的键值对分布 然而,线性探测容易产生“聚集现象”。具体来说,数组中连续被占用的位置越长,这些连续位置发生哈希冲 突的可能性越大,从而进一步促使该位置的聚堆生长,形成恶性循环,最终导致增删查改操作效率劣化。 值得注意的是,我们不能在开放寻址哈希表中直接删除元素。这是因为删除元素会在数组内产生一个空桶 None ,而当查询元素时,线性探测到该空桶就会 27, 30, 33, … } hash = {0, 3, 6, 0, 3, 6, 0, 3, 6, 0, 3, 6, … } 如果输入 key 恰好满足这种等差数列的数据分布,那么哈希值就会出现聚堆,从而加重哈希冲突。现在,假 设将 modulus 替换为质数 13 ,由于 key 和 modulus 之间不存在公约数,因此输出的哈希值的均匀性会明显 提升。 modulus = 13 key 元素存储在同一个链表中。然而,链表过长会降低查 询效率,可以通过进一步将链表转换为红黑树来提高效率。 ‧ 开放寻址通过多次探测来处理哈希冲突。线性探测使用固定步长,缺点是不能删除元素,且容易产生聚 集。多次哈希使用多个哈希函数进行探测,相较线性探测更不易产生聚集,但多个哈希函数增加了计算 量。 ‧ 不同编程语言采取了不同的哈希表实现。例如,Java 的 HashMap 使用链式地址,而 Python0 码力 | 382 页 | 17.60 MB | 1 年前3 Hello 算法 1.0.0 Golang版。 图 6‑6 开放寻址(线性探测)哈希表的键值对分布 然而,线性探测容易产生“聚集现象”。具体来说,数组中连续被占用的位置越长,这些连续位置发生哈希冲 突的可能性越大,从而进一步促使该位置的聚堆生长,形成恶性循环,最终导致增删查改操作效率劣化。 值得注意的是,我们不能在开放寻址哈希表中直接删除元素。这是因为删除元素会在数组内产生一个空桶 None ,而当查询元素时,线性探测到该空桶就会 27, 30, 33, … } hash = {0, 3, 6, 0, 3, 6, 0, 3, 6, 0, 3, 6, … } 如果输入 key 恰好满足这种等差数列的数据分布,那么哈希值就会出现聚堆,从而加重哈希冲突。现在,假 设将 modulus 替换为质数 13 ,由于 key 和 modulus 之间不存在公约数,因此输出的哈希值的均匀性会明显 提升。 modulus = 13 key 元素存储在同一个链表中。然而,链表过长会降低查 询效率,可以通过进一步将链表转换为红黑树来提高效率。 ‧ 开放寻址通过多次探测来处理哈希冲突。线性探测使用固定步长,缺点是不能删除元素,且容易产生聚 集。多次哈希使用多个哈希函数进行探测,相较线性探测更不易产生聚集,但多个哈希函数增加了计算 量。 ‧ 不同编程语言采取了不同的哈希表实现。例如,Java 的 HashMap 使用链式地址,而 Python0 码力 | 382 页 | 17.60 MB | 1 年前3
 Hello 算法 1.0.0b5 Golang版时,该空位可能导致 程序误判元素不存在。为此,通常需要借助一个标志位来标记已删除元素。 ‧ 容易产生聚集。数组内连续被占用位置越长,这些连续位置发生哈希冲突的可能性越大,进一步促使这 一位置的聚堆生长,形成恶性循环,最终导致增删查改操作效率劣化。 以下代码实现了一个简单的开放寻址(线性探测)哈希表。 第 6 章 哈希表 hello‑algo.com 118 ‧ 我们使用一个固定的键值对实例 27, 30, 33, … } hash = {0, 3, 6, 0, 3, 6, 0, 3, 6, 0, 3, 6, … } 如果输入 key 恰好满足这种等差数列的数据分布,那么哈希值就会出现聚堆,从而加重哈希冲突。现在,假设 将 modulus 替换为质数 13 ,由于 key 和 modulus 之间不存在公约数,输出的哈希值的均匀性会明显提升。 modulus = 13 key = 冲突元素存储在同一个链表中。然而,链表过长会降低查 询效率,可以进一步将链表转换为红黑树来提高效率。 ‧ 开放寻址通过多次探测来处理哈希冲突。线性探测使用固定步长,缺点是不能删除元素,且容易产生聚 集。多次哈希使用多个哈希函数进行探测,相较线性探测更不易产生聚集,但多个哈希函数增加了计算 量。 ‧ 不同编程语言采取了不同的哈希表实现。例如,Java 的 HashMap 使用链式地址,而 Python0 码力 | 379 页 | 30.70 MB | 1 年前3 Hello 算法 1.0.0b5 Golang版时,该空位可能导致 程序误判元素不存在。为此,通常需要借助一个标志位来标记已删除元素。 ‧ 容易产生聚集。数组内连续被占用位置越长,这些连续位置发生哈希冲突的可能性越大,进一步促使这 一位置的聚堆生长,形成恶性循环,最终导致增删查改操作效率劣化。 以下代码实现了一个简单的开放寻址(线性探测)哈希表。 第 6 章 哈希表 hello‑algo.com 118 ‧ 我们使用一个固定的键值对实例 27, 30, 33, … } hash = {0, 3, 6, 0, 3, 6, 0, 3, 6, 0, 3, 6, … } 如果输入 key 恰好满足这种等差数列的数据分布,那么哈希值就会出现聚堆,从而加重哈希冲突。现在,假设 将 modulus 替换为质数 13 ,由于 key 和 modulus 之间不存在公约数,输出的哈希值的均匀性会明显提升。 modulus = 13 key = 冲突元素存储在同一个链表中。然而,链表过长会降低查 询效率,可以进一步将链表转换为红黑树来提高效率。 ‧ 开放寻址通过多次探测来处理哈希冲突。线性探测使用固定步长,缺点是不能删除元素,且容易产生聚 集。多次哈希使用多个哈希函数进行探测,相较线性探测更不易产生聚集,但多个哈希函数增加了计算 量。 ‧ 不同编程语言采取了不同的哈希表实现。例如,Java 的 HashMap 使用链式地址,而 Python0 码力 | 379 页 | 30.70 MB | 1 年前3
共 14 条
- 1
- 2













