Golang在接入层长连接服务中的实践-黄欣Golang 在接入层长连接服务中的实践 黄欣 基础平台-架构部 目录 • 背景 • 架构 • 心得 目录 • 架构 • 心得 背景—why 长连接? • 业务场景 – 大量实时计算 • 司机乘客撮合 • 实时计价 – 高频度的数据交互 • 坐标数据 • 计价数据 – App和服务端双向可达 • 上行(抢单) • 下行(派单) 背景—why golang? • 开发效率 整体架构图 架构—接口设计 • 原则 – 扩展性 – 稳定性(最好不用升级) • 解决方法 – Protobuf(golang) – 接口设计分层 • 框架层:模块间通信协议(类似tcp/udp) • 业务层:bytes(类似应用层)留给业务自己定义就好了 架构—性能 • conn svr 架构—集群扩展 • Proxy本身无限扩容(无状态) • 依赖的存储可无限扩容(状态交给存储)0 码力 | 31 页 | 1.67 MB | 1 年前3
Hello 算法 1.1.0 Go版我深深赞同费曼教授所言:“Knowledge isn’t free. You have to pay attention.”从这个意义上看,这本 书并非完全“免费”。为了不辜负你为本书所付出的宝贵“注意力”,我会竭尽所能,投入最大的“注意力” 来完成本书的创作。 本人自知学疏才浅,书中内容虽然已经过一段时间的打磨,但一定仍有许多错误,恳请各位老师和同学批评 指正。 本书中的代码附有可一键运行的源文件,托管于 github ”。 2. 归:触发“终止条件”后,程序从最深层的递归函数开始逐层返回,汇聚每一层的结果。 而从实现的角度看,递归代码主要包含三个要素。 1. 终止条件:用于决定什么时候由“递”转“归”。 2. 递归调用:对应“递”,函数调用自身,通常输入更小或更简化的参数。 3. 返回结果:对应“归”,将当前递归层级的结果返回至上一层。 观察以下代码,我们只需调用函数 recur(n) ,就可以完成 间效率上与迭代相当。这种情况被称为尾递归(tail recursion)。 ‧ 普通递归:当函数返回到上一层级的函数后,需要继续执行代码,因此系统需要保存上一层调用的上下 文。 ‧ 尾递归:递归调用是函数返回前的最后一个操作,这意味着函数返回到上一层级后,无须继续执行其他 操作,因此系统无须保存上一层函数的上下文。 以计算 1 + 2 + ⋯ + ? 为例,我们可以将结果变量 res 设为函数参数,从而实现尾递归:0 码力 | 383 页 | 18.48 MB | 1 年前3
Hello 算法 1.0.0 Golang版我深深赞同费曼教授所言:“Knowledge isn’t free. You have to pay attention.”从这个意义上看,这本 书并非完全“免费”。为了不辜负你为本书所付出的宝贵“注意力”,我会竭尽所能,投入最大的“注意力” 来完成本书的创作。本人自知学疏才浅,书中内容虽然已经过一段时间的打磨,但一定仍有许多错误,恳请 各位老师和同学批评指正。 本书中的代码附有可一键运行的源文件,托管于 github ”。 2. 归:触发“终止条件”后,程序从最深层的递归函数开始逐层返回,汇聚每一层的结果。 而从实现的角度看,递归代码主要包含三个要素。 1. 终止条件:用于决定什么时候由“递”转“归”。 2. 递归调用:对应“递”,函数调用自身,通常输入更小或更简化的参数。 3. 返回结果:对应“归”,将当前递归层级的结果返回至上一层。 观察以下代码,我们只需调用函数 recur(n) ,就可以完成 间效率上与迭代相当。这种情况被称为「尾递归 tail recursion」。 ‧ 普通递归:当函数返回到上一层级的函数后,需要继续执行代码,因此系统需要保存上一层调用的上下 文。 ‧ 尾递归:递归调用是函数返回前的最后一个操作,这意味着函数返回到上一层级后,无须继续执行其他 操作,因此系统无须保存上一层函数的上下文。 以计算 1 + 2 + ⋯ + ? 为例,我们可以将结果变量 res 设为函数参数,从而实现尾递归:0 码力 | 382 页 | 17.60 MB | 1 年前3
Hello 算法 1.2.0 简体中文 Go 版我深深赞同费曼教授所言:“Knowledge isn’t free. You have to pay attention.”从这个意义上看,这本 书并非完全“免费”。为了不辜负你为本书所付出的宝贵“注意力”,我会竭尽所能,投入最大的“注意力” 来完成本书的创作。 本人自知学疏才浅,书中内容虽然已经过一段时间的打磨,但一定仍有许多错误,恳请各位老师和同学批评 指正。 本书中的代码附有可一键运行的源文件,托管于 github ”。 2. 归:触发“终止条件”后,程序从最深层的递归函数开始逐层返回,汇聚每一层的结果。 而从实现的角度看,递归代码主要包含三个要素。 1. 终止条件:用于决定什么时候由“递”转“归”。 2. 递归调用:对应“递”,函数调用自身,通常输入更小或更简化的参数。 3. 返回结果:对应“归”,将当前递归层级的结果返回至上一层。 观察以下代码,我们只需调用函数 recur(n) ,就可以完成 间效率上与迭代相当。这种情况被称为尾递归(tail recursion)。 ‧ 普通递归:当函数返回到上一层级的函数后,需要继续执行代码,因此系统需要保存上一层调用的上下 文。 ‧ 尾递归:递归调用是函数返回前的最后一个操作,这意味着函数返回到上一层级后,无须继续执行其他 操作,因此系统无须保存上一层函数的上下文。 以计算 1 + 2 + ⋯ + ? 为例,我们可以将结果变量 res 设为函数参数,从而实现尾递归:0 码力 | 384 页 | 18.49 MB | 10 月前3
go web 框架 严清web 框架 HTTP能⼒力力确实相对完整 • 即使有更更复杂的需求,即插即⽤用的包管理理 机制也能轻易易实现 Go 的⼤大糟点啊,学学 Rust • 第三⽅方框架都有学习成本,踩上坑就得潜 ⼊入源码求解决 其实就两三千⾏行行代码,都是精华,值得 看 如果你只写 Hello World 或 Todolist,或者是个⼈人开发者、爱折腾,没问题! 否则,还是使⽤用⼀一款框架吧!0 码力 | 23 页 | 333.12 KB | 1 年前3
Hello 算法 1.2.0 繁体中文 Go 版我深深認同費曼教授所言:“Knowledge isn’t free. You have to pay attention.”從這個意義上看,這本 書並非完全“免費”。為了不辜負你為本書所付出的寶貴“注意力”,我會竭盡所能,投入最大的“注意力” 來完成本書的創作。 本人自知學疏才淺,書中內容雖然已經過一段時間的打磨,但一定仍有許多錯誤,懇請各位老師與同學批評 指正。 本書中的程式碼附有可一鍵執行的原始檔,託管於 github capacity 觀察以上公式,當雜湊表容量 capacity 固定時,雜湊演算法 hash() 決定了輸出值,進而決定了鍵值對在雜 湊表中的分佈情況。 這意味著,為了降低雜湊衝突的發生機率,我們應當將注意力集中在雜湊演算法 hash() 的設計上。 6.3.1 雜湊演算法的目標 為了實現“既快又穩”的雜湊表資料結構,雜湊演算法應具備以下特點。 ‧ 確定性:對於相同的輸入,雜湊演算法應始終產生相同的輸出。這樣才能確保雜湊表是可靠的。 left subtree 左子树 左子樹 right subtree 右子树 右子樹 root node 根节点 根節點 leaf node 叶节点 葉節點 edge 边 邊 level 层 層 degree 度 度 height 高度 高度 depth 深度 深度 perfect binary tree 完美二叉树 完美二元樹 complete binary tree 完全二叉树0 码力 | 385 页 | 18.80 MB | 10 月前3
Hello 算法 1.0.0b4 Golang版省略所有系数。例如,循环 2? 次、5? + 1 次等,都可以简化记为 ? 次,因为 ? 前面的系数对时间复 杂度没有影响。 3. 循环嵌套时使用乘法。总操作数量等于外层循环和内层循环操作数量之积,每一层循环依然可以分别 套用上述 1. 和 2. 技巧。 以下示例展示了使用上述技巧前、后的统计结果。 ?(?) = 2?(? + 1) + (5? + 1) + 2 完整统计 (‑.‑|||) = float64) int { if n <= 1 { return 0 } return logRecur(n/2) + 1 } 线性对数阶 ?(? log ?) 线性对数阶常出现于嵌套循环中,两层循环的时间复杂度分别为 ?(log ?) 和 ?(?) 。 主流排序算法的时间复杂度通常为 ?(? log ?) ,例如快速排序、归并排序、堆排序等。 2. 复杂度 hello‑algo.com 25 个互不重复的元素,求其所有可能的排列方案,方案数量为: ?! = ? × (? − 1) × (? − 2) × ⋯ × 2 × 1 阶乘通常使用递归实现。例如以下代码,第一层分裂出 ? 个,第二层分裂出 ? − 1 个,以此类推,直至第 ? 层时终止分裂。 // === File: time_complexity.go === /* 阶乘阶(递归实现) */ 2. 复杂度 hello‑algo.com0 码力 | 347 页 | 27.40 MB | 1 年前3
Hello 算法 1.0.0b5 Golang版”。 2. 归:触发“终止条件”后,程序从最深层的递归函数开始逐层返回,汇聚每一层的结果。 而从实现的角度看,递归代码主要包含三个要素。 1. 终止条件:用于决定什么时候由“递”转“归”。 2. 递归调用:对应“递”,函数调用自身,通常输入更小或更简化的参数。 3. 返回结果:对应“归”,将当前递归层级的结果返回至上一层。 观察以下代码,我们只需调用函数 recur(n) ,就可以完成 间效率上与迭代相当。这种情况被称为「尾递归 tail recursion」。 ‧ 普通递归:当函数返回到上一层级的函数后,需要继续执行代码,因此系统需要保存上一层调用的上下 文。 ‧ 尾递归:递归调用是函数返回前的最后一个操作,这意味着函数返回到上一层级后,无需继续执行其他 操作,因此系统无需保存上一层函数的上下文。 以计算 1 + 2 + ⋯ + ? 为例,我们可以将结果变量 res 设为函数参数,从而实现尾递归。 省略所有系数。例如,循环 2? 次、5? + 1 次等,都可以简化记为 ? 次,因为 ? 前面的系数对时间复 杂度没有影响。 3. 循环嵌套时使用乘法。总操作数量等于外层循环和内层循环操作数量之积,每一层循环依然可以分别 套用第 1. 点和第 2. 点的技巧。 给定一个函数,我们可以用上述技巧来统计操作数量。 func algorithm(n int) { a := 1 // +0(技巧 1)0 码力 | 379 页 | 30.70 MB | 1 年前3
Golang 101(Go语言101 中文版) v1.21.aint64,反之亦然(因为它们都是 无名的并且它们的基类型的底层类型均为int64)。 4. 类型Ta的值不能直接被转换为类型Tb,即使是显式转换也是不行的。 但 是,通过上述三条事实,通过三层显式转换Tb((*MyInt)((*int64)(ta))), 一个类型为Ta的值ta可以被间接地转换为类型Tb。 这些指针类型的任何值都无法被转换到类型*uint64。 一个指针值不能和其它任一指针类型的值进行比较 字符串类型都是可比较类型。同一个字符串类型的值可以用==和!=比较运 算符来比较。 并且和整数/浮点数一样,同一个字符串类型的值也可以用 >、<、>=和<=比较运算符来比较。 当比较两个字符串值的时候,它们的底 层字节将逐一进行比较。如果一个字符串是另一个字符串的前缀,并且另 一个字符串较长,则另一个字符串为两者中的较大者。 一个例子: package main import "fmt" func main() 我们必须通过间接的 途径获得一个代表一个接口值的reflect.Value值。 被 一 个 reflect.Value 值 代 表 着 的 值 常 称 为 此 reflect.Value 值 的 底 层 值 (underlying value)。 reflect.Value类型有很多方法 。 我们可以调用这些方法来观察和操纵一个 reflect.Value属主值表示的Go值。 这些方法中的有些适用于所有种类类型的0 码力 | 608 页 | 1.08 MB | 1 年前3
Golang 101(Go语言101 中文版) v1.21.aint64,反之亦然(因为它们都是 无名的并且它们的基类型的底层类型均为int64)。 4. 类型Ta的值不能直接被转换为类型Tb,即使是显式转换也是不行的。 但 是,通过上述三条事实,通过三层显式转换Tb((*MyInt)((*int64) (ta))),一个类型为Ta的值ta可以被间接地转换为类型Tb。 这些指针类型的任何值都无法被转换到类型*uint64。 一个指针值不能和其它任一指针类型的值进行比较 IntegerType) string。 此函数用来从 一个任意(安全)byte指针派生出一个指定长度的字符串。 func StringData(str string) *byte。 此函数用来获取一个字符串底 层字节序列中的第一个byte的指针。 func SliceData(slice []ArbitraryType) *ArbitraryType。 此函数 用来获取一个切片底层元素序列中的第一个元素的指针。 } 我们应该将Value方法的属主参数类型更改为指针类型*Counter来避免复制 sync.Mutex值。 Go官方工具链中提供的go vet命令将提示此例中的Value方法的声明可能是一个潜 在的逻辑错误。 在错误的地方调用sync.WaitGroup.Add方法 每个sync.WaitGroup值内部维护着一个计数。此计数的初始值为0。 如果一个 sync.WaitGroup值0 码力 | 591 页 | 21.40 MB | 1 年前3
共 41 条
- 1
- 2
- 3
- 4
- 5













