Ryo's blog

归档 · 全部

首页

关于

归档

loading..
GolangCompiler

Golang 编译器优化那些事

一、背景去年写了一篇 Golang Memory Model 文章。当时在文章里面贴了验证一个线程可见性问题Demo,具体代码如下: func main() { running := true go func() { println("start thread1") count := 1 for running { count++ } println("end thread1: count =", count) // 这句代码永远执行不到为什么? }() go func() { println("start thread2") for..

更多
loading..
Golang

Golang Memory Model

一、背景1.1 一个 Code Review 引发的思考一个同学在 Golang 项目里面用 Double Check(不清楚的同学可以去百度搜下,Java中比较常见)的方式实现了一个单例。具体实现如下: var ( lock sync.Mutex instance *UserInfo ) func getInstance() (*UserInfo, error) { if instance == nil { //---Lock lock.Lock() defer lock.Unlock() if instance == nil { instance = &UserInfo{..

更多
loading..
ChatRoom

《基于 Rust 实现一个加密的 IM 聊天室》

一、背景最近在看Rust相关的东西,想找个项目用Rust练下手,熟悉一下Rust基本特性。然后聊天工具是我们日常最常用的一个软件,我一直想自己写个安全的聊天软件(程序员一般都不相信非开源的程序)。 最终实现的效果图如下(项目地址): 二、技术选型说到IM软件,我们常常就会想到一些特性,比如实时性、安全性、可靠性、跨平台兼容性、消息有序等等,我们看下常见的一些IM的技术方案有哪些。 2.1 HTTP 轮询Http 轮询顾名思义,通过不停轮询的方式来判断是否有收到新的消息。轮询还分为长轮询和短轮询两种。 短轮询(Short Polling): 短轮询是客户端定期向服务器发送请求,查询是否有新数据。通常,客户端会在每个请求之间设置一个固定时间间隔。以下是短轮询的基本工作流程: 客户端向服务器发送HTTP请..

更多
Golang

深入理解 Golang Stack

一、基础知识1.1 Linux 虚拟地址空间布局我们知道CPU有实模式和保护模式,系统刚刚启动的时候是运行在实模式下,然后经过一系列初始化工作以后,Linux会把CPU的实模式改为保护模式(具体就是修改CPU的CR0寄存器相关标记位),在保护模式下,CPU访问的地址都是虚拟地址(逻辑地址)。Linux 为了每个进程维护了一个单独的虚拟地址空间,虚拟地址空间又分为“用户空间”和“内核空间”。 虚拟地址空间更多相关可以看Linux内核虚拟地址空间这篇文章。 1.2 Golang 栈和虚拟地址空间栈的区别Golang 的内存管理是用的 TCMalloc(Thread-Caching Malloc)算法, 简单点说就是 Golang 是使用 mmap 函数去操作系统申请一大块内存,然后把内存按照 ..

更多
MySQL

MySQL Insert 死锁问题研究

背景不想看废话的,建议直接去最后看死锁的本质原因。 问题背景线上一个很简单结构的表,报insert死锁,这个表基本上只有insert操作,所以引出一个问题insert 和insert之间为什么会死锁? 顺便说下我们线上库的隔离级别都是RC,日志格式是ROW,我下面所有测试都是在RC下。 *** (1) TRANSACTION: TRANSACTION 2404187192, ACTIVE 0 sec inserting mysql tables in use 1, locked 1 LOCK WAIT 8 lock struct(s), heap size 1136, 2 row lock(s) MySQL thread id 118913019, OS thread handle 140411115681..

更多
loading..
LinuxMemory

Linux内核虚拟地址空间

x86-32位虚拟地址空间就我们所知,Linux内核一般将处理器的虚拟地址空间划分为两个部分。底部比较大的部分用于用户进程,顶部则专用于内核。虽然(在两个用户进程之间的)上下文切换期间会改变下半部分,但虚拟地址空间的内核部分总是保持不变。 Linux将虚拟地址空间划分为:0~3G为用户空间,3~4G为内核空间 点我查看原图 用户地址空间 保留区 - 0x08048000位于虚拟地址空间的最低部分,未赋予物理地址。任何对它的引用都是非法的,用于捕捉使用空指针和小整型值指针引用内存的异常情况。 它并不是一个单一的内存区域,而是对地址空间中受到操作系统保护而禁止用户进程访问的地址区域的总称。大多数操作系统中,极小的地址通常都是不允许访问的,如NULL。C语言将无效指针赋值为0也是出于这..

更多
Book

《认知觉醒》

序、开启自我改变的原动力内观自己,摆脱焦虑;外观世界,接力前行 一小部分人幸运些,在合适的年纪“睁开了眼睛”。他们跳出了成长的陷阱,开始刻意提升自己,为未来美好的生活做准备。他们慢慢甩开了大队伍,走在了同龄人的前列,然而很快遇到了瓶颈:想勤奋,却总是敌不过惰性;想努力,却总是陷入低效的状态;想精进,面前却总是弯路不断;读了很多书,都忘了;付出很多努力,都白费了。他们仿佛越使劲越困惑,越努力越迷茫。 我发现每天有事情做不代表觉醒,每天都努力也不代表觉醒,真正的觉醒是一种发自内心的渴望,立足长远,保持耐心,运用认知的力量与时间做朋友;我发现人与人之间的根本差异是认知能力上的差异,因为认知影响选择,而选择改变命运,所以成长的本质就是让大脑的认知变得更加清晰 一、大脑 一切问题的起源第一节 大脑:重新认识你自..

更多
ele

MySQL 基础

其他 MySQL 相关技术沉淀文章 MySQL Insert 死锁问题研究 MySQL 自增列 Duplicate Error 问题分析 MySQL DateTime和Timestamp时区问题 一、基础1.1 常用索引有哪些普通索引、唯一索引、主键索引、组合索引、全文索引 1.2 聚集索引和非聚集索引区别聚集索引(Clustered Index)和非聚集索引(Non-clustered Index)是两种不同类型的数据库索引,它们的区别如下: 聚集索引(Clustered Index): 聚集索引中的数据行和索引的顺序相同,即它将数据行本身和索引按照相同的排序方式存储在一起。 一个表只能有一个聚集索引,因为数据行只能以一种顺序存储。 聚集索引通常用主键建立,但也可以使用其他具有唯一约束的列。 数据..

更多
Book

《非暴力沟通的父母语言》

第一章 停止吼叫,你可以这样做关键词:倾听+接纳 用说教、打骂、威胁、警告、贿赂等方法让孩子变得听话,根本无济于事。任何以牺牲亲子关系为代价的沟通方式都是失败的。或许孩子在你的压迫下会变得看起来很听话,但这并不是长期而有效的管教方式,也不是有效的沟通方式。 1.1、有效的沟通从倾听开始 放下手中的事,认真倾听孩子的心声。或许你正在看书,打扫房间,或者是追剧……不管你在做什么,请暂时停下来,和孩子一起坐下来,注视着孩子的眼睛,认真地听他想说什么。只要我们认真地倾听了,即使我们的沟通技巧稍微欠缺,也能收到良好的沟通效果。 对孩子的话题表现出极大的兴趣。虽然孩子所说的事在我们看来也许有些幼稚,但是请闭上我们的嘴巴,把说话的权利留给孩子,把自己当作一个容器,不管孩子说的是什么,都毫无保留地放进去,不..

更多
ele

操作系统基础

其他 OS 相关技术沉淀文章 Linux内核虚拟地址空间 Linux0.11启动过程 一、基础1.1 进程、线程、协程区别 进程:进程是操作系统管理和调度的基本单位,拥有独立的内存空间和系统资源,通常适用于不同程序的并发执行。 线程:进程内的执行单位,共享相同的内存空间和资源,适用于一个程序内部的并发和多任务处理。 协程:编程语言实现的轻量级线程,在单个线程上实现多任务的协作式并发,适用于高并发场景和异步任务处理。 1.2 进程、线程上下文切换进程上下文切换开销: 进程上下文切换涉及保存当前运行进程的CPU寄存器状态、程序计数器、堆栈指针、内存管理信息(如页表)等,并恢复新进程的上下文信息。这些操作会带来很大的开销,因为: 上下文切换需要CPU从用户态切换到内核态,导致额外的运行时间。 需要保存和恢..

更多
ele

Golang基础

其他 Golang 相关技术沉淀文章 Golang Memory Model Golang 编译器优化那些事 深入理解 Golang Stack Golang “锁”事 Golang Context 详解 Go 泛型初窥 Go源码——Sync.Mutex Go源码——runtime.semaphore Go源码——runtime.mutex Go源码——Sync.Map的前生今世 GO非类型安全指针-Unsafe.Pointer Go 自定义引用包的域名 一次线上内存使用率异常问题排查 Go for-range 的奇技淫巧 Golang RWMutext 代码走读 Golang 内存对齐问题 Golang基础 - 脑图链接

更多
ele

网络基础知识

一、TCP基础知识1.1 TCP和UDP的区别?TCP是面向连接的协议,在收发数据前必须和对方建立可靠的连接,建立连接的3次握手、断开连接的4次挥手,为数据传输打下可靠基础; UDP是无连接的,不可靠传输,尽最大努力交付数据,协议简单、资源要求少、传输速度快、实时性高的特点,适用于对传输效率要求高,但准确率要求低的应用场景,比如域名转换(DNS)、远程文件服务器(NFS)等。 1.2 TCP 为什么需要三次握手?为什么需要四次挥手?如何保证可靠?为什么需要三次握手? 三次握手能确保双发的收发能力(确定双通道通畅)是OK。 为什么需要四次挥手 因为TCP是全双工协议,双方都可以发送和接收数据。当一方决定终止连接时,另一方可能还有数据需要发送。 如何保证可靠? 错误检测:TCP使用校验和功能来检测数据包在..

更多
ele

缓存基础技术

其他 Redis 相关技术沉淀文章 Redis 源码分析(一) :sds Redis 源码分析(二) :ADList Redis 源码分析(三) :dict Redis 源码分析(四) :intset Redis 源码分析(五) :ziplist Redis 源码分析(六) :quciklist Redis 源码分析(七) :skiplist Redis 高可用解决方案总结 基础1.1 Redis 常用的数据结构Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。 Sting 、SDS(embstr、raw) List qucklist (ziplist、linklist) Set (dict、 ..

更多
BookRust

《Rust 编程第一课》

《陈天 · Rust 编程第一课》 一、所有权 脑图链接 所有权和生命周期是Rust和其它编程语言的主要区别,也是Rust其它知识点的基础。 1.1、变量在函数调用时发生了什么fn main() { // vec 动态数组因为大小在编译期无法确定,所以放在堆上, // 并且在栈上有一个包含了长度和容量的胖指针指向堆上的内存。 let data = vec![10, 42, 9, 8]; let v = 42; if let Some(pos) = find_pos(data, v) { println!("Found {} at {}", v, pos); } } fn find_pos(data: Vec<u32>, v: ..

更多
BookCompiler

《编译原理之美》

0、为什么你要学习编译原理? 1、理解代码:编译器的前端技术 1.1 词法分析Lexical Analysis 通常,编译器的第一项工作叫做词法分析。就像阅读文章一样,文章是由一个个的中文单词组成的。程序处理也一样,只不过这里不叫单词,而是叫做词法记号,英文叫 Token。 也可以用词法分析器的生成工具来生成,比如 Lex(或其 GNU 版本,Flex)。这些生成工具是基于一些规则来工作的,这些规则用正则文法表达,符合正则文法的表达式称为正则表达式。生成工具可以读入正则表达式,生成一种叫有限自动机的算法,来完成具体的词法分析工作。 不要被正则文法(Regular Grammar)和有限自动机(Finite-state Automaton,FSA,or Finite Automaton)吓到。正则文法是一..

更多
Golang

Golang “锁”事

一、 Go 同步原语 sync.Cond -> notifyList -> runtime.mutex、atomic sync.WaitGroup -> atomic、 runtime.sema sync.Map -> sync.Mutex、atomic sync.Once -> sync.Mutex、atomic sync.RWMutex -> sync.Mutex、atomic sync.Mutex -> runtime.sema channel -> runtime.mutex sync.Mutex和runtime.mutext区别:简单说就是sync.Mutex是用户层的锁,Lock抢锁失败会造成goroutine阻塞(会调用gopark)。run..

更多
Golang

Golang Context 详解

基于 Go 1.18 源码分析 一、引言1.1 什么是 Context?Context是Go 1.7引入的一个标准库,官方 blog 里面介绍,最早是Google内部使用的一个库,主要用于在一个Request对应的多个Goroutine中传递数据,数据主要分为两种: 请求的基本信息,比如用户鉴权信息、请求的Request-ID等等。 请求的Deadline,如果请求被Cancel或者Timeout,能够控制多个Goroutine会返回。 整个 context.go 加上注释也就600行左右。核心就是Context type : type Context interface { // 获取 DeadLine 时间,使用 WithDeadline 和 WithTimeout 才有 Deadl..

更多
Algorithm

牛顿迭代法求开方

求一个数的开平方我们假设这个数是a,如何先快速求出√a的值? 我们可以把这个题目转化成一个几何问题。如下图: 可以转换为,求公式Y = X^2 - a,(√a,0)的值。 我们现在抛物线上任意取一点(x0,x0^2 - a), 然后基于这一点画一个切线,切线的方程记为Y = KX + b。 切线的斜率 K,我们可以对抛物线求导,得到 K = 2 * x0 带入到切线的方程可以得 Y = 2 * x0 * X + b 因为切线经过点(x0,x0^2 - a),带入切线方程,就有 x0^2 - a = 2 * x0^2 + b 转而得到b = -x0^2 - a 然后带入到之前的切线的方程 Y = 2 * x0 * X + b 可得 Y = 2 * x0 * X - x0^2 - a,把。 把(x1, 0)..

更多
Book

《架构实战案例解析》

摘录与 《架构实战案例解析》 架构的本质物理学中有个很著名的“熵增定律”:一个封闭系统,都是从有序到无序,也就是它的熵(即混乱程度)会不断地增加,最终系统会彻底变得无序。 一方面,随着业务需求的增加,我们会往系统里不停地添加业务功能;另一方面,随着访问量的不断增加,我们会不断通过技术手段来加强系统非业务性功能。如果事先不做良好的设计,随着时间的推进,整个系统野蛮生长,就会逐渐碎片化,越来越无序,最终被推倒重来。 不过,自然界中的生物可以通过和外界交互,主动进行新陈代谢,制造“负熵”,也就是降低混乱程度,来保证自身的有序性,继续生存。比如,植物通过光合作用,把光能、二氧化碳和水合成有机物,以此滋养自己,延续生命。对于软件系统,我们也可以主动地调整系统各个部分的关系,保证系统整体的有序性,来更好地适应不断增..

更多
Book

《精通正则表达式》

摘录与 《精通正则表达式》 一、正则表达式入门正则表达式(Regular Expression)是强大、便捷、高效的文本处理工具。正则表达式本身,加上如同一门袖珍编程语言的通用模式表示法(general pattern notation),赋予使用者描述和分析文本的能力。配合上特定工具提供的额外支持,正则表达式能够添加、删除、分离、叠加、插入和修整各种类型的文本和数据。 1.1 检索文本文件:Egrep egrep -i '^func' cache.go // 匹配 func 开头的 egrep -i '^$' cache.go | wc -l // 计算文件 空行数 egrep '\<ctx' cache.go // 含有 ctx 开头单词的行 egrep 'Get\>' cache...

更多
Book

《正则表达式必知必会》

摘录与 《正则表达式必知必会》 零、快速上手 [abc] 匹配单个字符a、b、c . 匹配除换行符(\n、\r)之外的任何单个字符。 [0-9]等价[0123456789] 含义是匹配一个数字,输入 123。 匹配三个结果 1、2、3。-(连字符)是一个特殊的元字符,它只有出现在[和]之间的时候才是元字符 \d 等价上面的[0-9]\w 匹配字母、数字、下划线。等价于[A-Za-z0-9_]。^[0-9]表示匹配一个非数字。^有取反的意思[A-Za-z0-9]等价[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789]. * 匹配前面的子表达式零次或多次。例如,zo* 能匹配z以及zoo。* 等价于{0,}。 + 匹配前面的..

更多
BookRust

《Hello Rust Async》

摘录与 Asynchronous Programming in Rust 一、Getting Started1.1 Rust 的异步 vs 其他语言的尽管很多语言都支持异步编程,但实现细节上有很多不一样。Rust的异步实现和大部分语言的在以下方面有区别: Rust中 Futures 是惰性的,并且只有被轮询才会进一步执行。丢弃(Dropping)一个future可以阻止它继续执行。 Rust中的异步是零成本的,这意味着你只需要为你所使用的东西付出代价。特别来说,你使用异步时可以不需要堆分配或动态分发,这对性能来说是好事!这也使得你能够在约束环境下使用异步,例如嵌入式系统。 Rust不提供内置运行时。相反,运行时由社区维护的库提供。 Rust里单线程的和多线程的运行时都可用,而他们会有不同的优劣。 Dem..

更多
Rust

《Hello Rust》

摘录于 Rust 程序设计语言 中文版 零、Why Rust Rust 是一种令人兴奋的新编程语言,它可以让每个人编写可靠且高效的软件。 它可以用来替换C/C++,Rust和他们具有同样的性能,但是很多常见的bug在编译时就可以被消灭。 Rust是一种通用的编程语言,但是他更善于以下场景: 需要运行时的速度 需要内存安全 更好的利用多处理器 Rust安全、无需GC、易于维护、调试、代码安全高效。 Rust优点,性能、安全、无所畏惧的并发。 Rust特别擅长的领域 高性能的 Web Service WebAssembly 命令行工具 网络编程 嵌入式设备 系统编程 Google:新操作系统Fuschia,其中Rust代码量大约占30% Amazon:基于Linux开发的直接可以在裸机、虚拟机上运行容..

更多
Book

《靠谱》

摘录与 《靠谱》 第一章 靠谱:成功的进阶方法论所谓靠谱,就是收到做到、说到做到、想到做到。 靠谱,就是不断交付确定靠谱的人就是收到做到、说到做到、想到做到的人。靠谱的事就是难而正确的事。靠谱的关系就是双向奔赴或有能量流入的关系。我们一生都应该追随这些靠谱的事物。 靠谱,有以下三层含义 第一,总是能完成目标,说到做到。只要承诺了,就一定会按时,按要求,保质保量地交付成果。 第二,总是能完成指令,收到做到。你安排一件事他能完成,你安排多件事他仍旧能完成。一个靠谱的人,收到指令后会回复;遇到困难会沟通;项目进展会按节点通报;安排会落实。他会说到做到,尽心尽力,有始有终,积极主动;不玻璃心,没有惰性,不骄横。他能深刻地意识到,这不是繁文缛节,这是一个公司的基本规范。 第三,总是能解决难题,想到做到。靠谱的..

更多
Book

《学习高手》- Part

摘录与《学习高手》 哈佛学生的24小时,到底是如何度过的?6:30am 起床:在学校时总能形成较稳定的生物钟。有时即使不开闹铃,也能在6:30前后不超过10分钟的区间内醒来。 warm-up俯卧撑:我的惯常“醒盹”做法。伸个懒腰活动一下筋骨,然后快速做30个俯卧撑,不多不少。喘口气,清醒效果特好。推荐大家(尤其男生)试试。 当日To-do list确认:用不超过5分钟的时间列好当天所有要完成的To-do’s,涵盖学习、工作、社交等不同板块事项,在一日之始做到心中有数,随后才能有条不紊地高效做事。 6:40am 起床工序完成后,喝一杯常温水,简单地洗漱,吃一点黑巧克力,然后出门去健身房。入学以来我都住校园宿舍,走路三分钟就可以到商学院专属的健身中心,特别方便。 6:45am—7:25am 到达健身房,拉..

更多
Linux

Linux0.11启动过程

零、概览首先申明,下面启动过程是基于 Linux 0.11 源码的分析的结果 Linux 0.11 源码 开机CPU的PC(x86也叫IP)寄存器内容固定初始化为0xFFFF0(地址为BIOS的ROM程序地址)。开机会首先执行ROM中的程序。 BIOS的ROM程序会读取硬盘启动区(第一扇区512字节)的bootscet程序到内存的0x7c00位置 把从bootscet程序从 0x7c00 到 0x90000,历史兼容原因只能先写到0x7c00,然后再复制到0x90000为什么主引导记录的内存地址是0x7C00?。 设置ds、es、ss 几个寄存器的基地址为0x9000,sp设置为0xFF00。 把操作系统setup和system两个程序加载到内存中。 把system代码复制到零地址处,覆盖掉0x..

更多
Book

《十分钟冥想》

摘录与 《十分钟冥想》 导言冥想和心灵冥想竟然有如此广泛的好处,也许你觉得有点儿难以置信,但是仔细想一想就会发现,你所做的任何需要用心的事情都能从冥想中受益,这就如同调整计算机硬盘的分区。难道有什么事是你不需要用心的吗?因此,考虑到心灵在我们生活中起到的重要作用,这场冥想引发的革命竟然没有更早发生,真是值得我们关注。我们不会对身体锻炼有丝毫踌躇(好吧,大多数情况下如此),却把心灵健康放在不起眼的位置。到底是因为没人能看到我们的心灵,还是因为我们觉得这是一场注定要失败的行动,这些并不重要。事实上,我们的整个生活都是通过心灵来体验的。我们的人生幸福感、满足感以及积极的人际关系都来自我们的内心。因此,每天花上几分钟来训练和养护我们的心灵吧!这才是明智的做法。 科学最近这些年来,核磁共振技术的进步,再加上完善..

更多
LLVM

LLVM编译器基础知识

一、基础概念1.1 Interpreter 和 Compile Interpreter 解释器 Compile 编译器 程序步骤 1、创建代码 2、没有文件链接或机器代码生成 3、源语句在执行过程中逐行执行 1、创建代码 2、将解析或分析所有语言语句的正确性 3、将把源代码转换为机器码 4、链接到可运行程序 5、运行程序 Input 每次读取一行 整个程序 Output 不产生任何的中间代码 生成中间目标代码 工作机制 编译和执行同时进行 编译在执行之前完成 存储 不保存任何机器代码 存储编译后的机器代码在机器上 执行 程序执行是解释过程的一部分,因此是逐行执行的 程序执行与编译是分开的,它只在整个输出程序编译后执行 生成程序 不生成输出程序,所以他们在每次执行过程中都要..

更多
Linuxebpf

《eBPF 核心技术与实战》

概览eBPF 是什么呢? 从它的全称“扩展的伯克利数据包过滤器 (Extended Berkeley Packet Filter)” 来看,它是一种数据包过滤技术,是从 BPF (Berkeley Packet Filter) 技术扩展而来的。 BPF 提供了一种在内核事件和用户程序事件发生时安全注入代码的机制,这就让非内核开发人员也可以对内核进行控制。随着内核的发展,BPF 逐步从最初的数据包过滤扩展到了网络、内核、安全、跟踪等,而且它的功能特性还在快速发展中,这种扩展后的 BPF 被简称为 eBPF(相应的,早期的 BPF 被称为经典 BPF,简称 cBPF)。实际上,现代内核所运行的都是 eBPF,如果没有特殊说明,内核和开源社区中提到的 BPF 等同于 eBPF。 tcpdump 和 BCC 之所以..

更多
Golang

Go 泛型初窥

一、基础知识1.1 形参和实参func min(a, b int) int { if a > b { return b } return a } func main() { minNum := min(100, 200) } 如上a、b叫形参(parameter),100和200叫实参(argument)。 1.2 类型形参、类型实参、类型约束、类型形参列表func sumNum[T int32 | float32](n []T) T { var s T for _, item := range n { s += item } return s } func main() { data1 :=..

更多
GolangGoSourceCode

Go源码——Sync.Mutex

一、背景sync.Mutex是我们常用到的一把锁。网上讲这个锁的文章也比较多,这里面主要是为了简单做个自我总结。 Sync.Mutex 慢路径底层依赖的是runtime_SemacquireMutex和runtime_Semrelease,对这个不了解可以先去看下 runtime.semaphore 。 二、Sync.Mutex 源码2.1 发展历史sync.Mutex第一版 代码 是2008年的时候 @rsc 提交的。最早的实现比较简单,是通过简单的CAS加信号量的方式来实现的。信号量具体可以参考 runtime-sema 这篇文章。 @dvyukov 2011年的时候,提交了第一次优化了 sync: improve Mutex to allow successive acquisitions,这一版中加..

更多
GolangGoSourceCode

Go源码——runtime.semaphore

一、背景sync.Mutex里面用了runtime_SemacquireMutex和runtime_Semrelease,所以看下这个runtime的信号量是如何实现的。 二、基础知识2.1 信号量信号量(英语:semaphore)又称为信号标,是一个同步对象,用于保持在0至指定最大值之间的一个计数值。当线程完成一次对该semaphore对象的等待(wait)时,该计数值减一;当线程完成一次对semaphore对象的释放(release)时,计数值加一。当计数值为0,则线程等待该semaphore对象不再能成功直至该semaphore对象变成signaled状态。semaphore对象的计数值大于0,为signaled状态;计数值等于0,为nonsignaled状态。 信号量的概念是由荷兰计算机科学家艾兹赫..

更多
GolangGoSourceCode

Go源码——runtime.mutex

一、背景在Go的runtime包中封装了一个 mutux ,这个mutex被runtime包中大量组件使用,比如 channel、netpoll、检查活跃的定时器 等等。 sync.Mutex和runtime.mutext区别:简单说就是sync.Mutex是用户层的锁,Lock抢锁失败会造成goroutine阻塞(会调用gopark)。runtime.mutex 是给 runtime使用的锁,Lock抢锁失败,会造成m阻塞(线程阻塞,底层调用的futex)。 二、基础知识2.1 MutexMutex 全称是Mutual Exclusion ,俗称互斥体或者互斥锁。是一种用于多线程编程中,防止两条线程同时对同一公共资源(比如全局变量)进行读写的机制。 2.2 mmap 函数mmap它的主要功能是将一个虚拟内..

更多
GolangGoSourceCode

Go源码——Sync.Map的前生今世

一、背景前段时间有个朋友来问我Go的Sync.Map性能怎么样,一般什么场景推荐使用。一句话介绍的话,就是Sync.Map底层有两个map,一个是read,一个是dirty,读写read中数据不需要加锁,读写dirty不用需要加锁,适用于读多写少的场景。 碎碎念其实2020年的时候Go源码里面一些比较常用的包都大致看了一遍,当时跟槊槊、大飞哥、周老板空闲时间天天讨论各种技术细节,包括但不仅限于操作系统、MySQL、Redis、分布式、Go、项目架构方法论等。很多时候观点不合还会争的面红耳赤,最后还会上升到人生攻击,你不服我,我也不服你(实际上互有对错,我也被打过几次脸)。因为有的东西,网上有很多错误的资料,导致我养成了一个习惯,找资料的时候我一般都是去看一些权威的技术书或者直接去看开源组件源码,能用代码说的..

更多
Book

《五蠹》

摘录与 《五蠹》 一、背景看 《Clean Architecture》的时候,看到书里面介绍什么架构师,大致内容如下。 首先,软件架构师自身需要是程序员,并且必须一直坚持做一线程序员,绝对不要听从那些说应该让软件架构师从代码中解放出来以专心解决高阶问题的伪建议。不是这样的!软件架构师其实应该是能力最强的一群程序员,他们通常会在自身承接编程任务的同时,逐渐引导整个团队向一个能够最大化生产力的系统设计方向前进。也许软件架构师生产的代码量不是最多的,但是他们必须不停地承接编程任务。如果不亲身承受因系统设计而带来的麻烦,就体会不到设计不佳所带来的痛苦,接着就会逐渐迷失正确的设计方向。 然后就吐槽了下某些 PPT架构师 只会脱离业务去谈一些高大上的架构,完全都落不了地。然后某个博览群书的技术大佬推荐我看下《五..

更多
Golang

GO非类型安全指针-Unsafe.Pointer

一、背景朋友发了一段测试代码里面不正确的使用了atomic.StorePointer,导致GC的时候程序Panic了。 var current int64 atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&current)), unsafe.Pointer(&latest)) 为什么会Panic这里先按下不表。之前对 unsafe.Pointer 用的并不多,也没有系统了解过。所以就想系统看下。看了下 unsafe.Pointer 官方文档还挺详细的,可能只之前使用出错的人太多了,所以 rsc 单独提了一个 CR 来说明unsafe.Pointer的用法。 二、unsafe.Pointerunsafe.Pointer表示指向任意类型..

更多
Golang

Go 自定义引用包的域名

一、 背景最近在看 Go源码的时候,发下部分库最早是在 x-pkg 里面的,经过一段时间迭代才进了runtime包里面。 x-pkg 里面介绍了用途和源码地址。 golang.org/x 文档 我发现 x-pkg 的源码地址都在 https://go.googlesource.com, 但是我们项目里面导入某个x-pkg库的路径确是 import "golang.org/x/sync/semaphore" 比较好奇,这import的别名是在哪里做的,感觉是个挺冷门的知识,于是搜了下相关资料。 二、实现步骤找到了官网相关资料: hdr-Remote_import_paths 简单说就是在你的网址里面加入如下信息。 <meta name="go-import" content="example.or..

更多
Book

《人月神话》

摘录与 《人月神话》 什么是人月神话? 一个项目有10人/月的工作量,把人增加到100人,所以只用3天就能开发完,这就是人月神话。 一个谬误的思考方式是在估计和进度安排中使用的工作量单位:人月。成本的确随开发产品的人数和时间的不同,有着很大的变化,进度却不是如此。因此我认为用人月作为衡量一项工作的规模是一个危险和带有欺骗性的神话。它暗示着人员数量和时间是可以相互替换的。 一、焦油坑(The Tar Pit)史前史中,没有别的场景比巨兽在焦油坑中垂死挣扎的场面更令人震撼。上帝见证着恐龙、猛犸象、剑齿虎在焦油中挣扎。它们挣扎得越是猛烈,焦油纠缠得越紧,没有任何猛兽足够强壮或具有足够的技巧,能够挣脱束缚,它们最后都沉到了坑底。 过去几十年的大型系统开发就犹如这样一个焦油坑,很多大型和强壮的动物在其中剧烈地挣..

更多
Book

《原则:应对变化中的世界秩序》

摘录与 《原则:应对变化中的世界秩序》 一、大周期概述人类的生产率是驱动世界总财富、权力和生活水平逐步提高的最重要的力量。随着时间的推移,生产率稳步提高(生产率是人均产出,受人类的学习、积累和发明的驱动)。然而,不同群体的生产率增速有差异,其原因总是一样的:不同的教育质量、创造力、职业道德以及将想法转化为产出的经济体制。决策者需要理解这些原因,以使自己的国家获得可能实现的最佳结果。投资者和公司也需要理解这些原因,以便确定最佳的长期投资对象。 下图及下页图显示过去500年的人均产出[即实际GDP(国内生产总值)估值]和预期寿命。这可能是两种公认的福祉衡量方法(但数据可能并不精确)。你可以看到这些数据渐进的上行幅度相对于围绕趋势线的波动幅度。 与围绕趋势线的波动相比,这些上行趋势非常明显,这一事实表明,相..

更多
Book

《非暴力沟通》

摘录与 《非暴力沟通》 一、由衷的给予非暴力沟通帮助我们与他人和自己建立连结,使我们得以流露与生俱来的慈悲之心。它指引我们通过将注意力聚焦在观察、感受、需要和请求这四个要素,来重新构建表达和聆听的方式。 非暴力沟通培育深度倾听的能力,让我们带着尊重和同理心对待他人,并且发自内心地相互给予。用非暴力沟通的方式,有的人学会了爱自己,有的人在人际关系中创造了更深厚的连结,有的人在工作或政治领域中建立了更有效的关系。在世界各地,非暴力沟通还被用来调和各个层面的纠纷和冲突。 二、疏离生命的语言由衷的给予和接受,是人类天性所乐见的。然而我们习得了太多疏离生命的语言形式,导致我们的说话和行为方式给他人和自己带来伤害。其中的一种形式是道德评判,即认为那些不符合我们价值观的人是不对的、不好的。另一种形式是做比较,让人们..

更多
Golang

一次线上内存使用率异常问题排查

一、背景朋友的一个服务,某个集群内存的RSS使用率一直在80%左右,他用的是8核16G, 双机房一共206个实例。 但是在pprof里面查的堆内存才使用了6.3G左右,程序里面主要用了6G的LocalCache所以heap用了6.3G是符合预期的。 朋友让我帮忙看下,额外的内存到底是被啥占用了。 二、基础知识2.1 TCMalloc 算法Thread-Caching Malloc 是Google开发的内存分配算法库,最开始它是作为Google的一个性能工具库perftools的一部分。 TCMalloc是用来替代传统的malloc内存分配函数。它有减少内存碎片,适用于多核,更好的并行性支持等特性。 2.2 mmap 函数mmap它的主要功能是将一个虚拟内存区域与一个磁盘上的文件关联起来,以初始化这个虚..

更多
MySQL

MySQL 自增列 Duplicate Error 问题分析

一、背景最近我们在做线上的数据迁移测试(可以理解就是把A数据中心的数据迁移到B数据中心,A和B数据中心的MySQL是同构的,迁移过程中,A、B的MySQL都有正常的业务数据写入。每次我们触发迁移的时候,就有业务方反馈他们写入数据的时候就会有Error 1062: Duplicate entry 'xxx' for key 'PRIMARY'这样的错误。业务方同学还反馈他们写数据的时候并没有指定ID,所以他们对这样的报错比较困惑,具体他们的数据写入的伪代码如下: type Data struct { ID int64 `gorm:"primaryKey;column:id"` PageID string `gorm:"column:page_id`..

更多
Golang

Go for-range 的奇技淫巧

背景朋友发了两个代码片段给我看,让我猜输出的内容是啥。具体代码如下: // Demo1 // 1. 这个循环是否能停下来? // 2. 如果能停下来,打印的 arr 内容是什么? arr := []int{1, 2, 3} for _, v := range arr { arr = append(arr, v) } fmt.Println(arr) // Demo2 // 1. idx 和 value 输出多少? // 2. 输出几行? str := "你好" for idx, v := range str { fmt.Printf("idx = %d , value = %c\n", idx, v) } 不卖关子,先说下第一个Demo输出的是: [1 2 3 1 2 3] 第二..

更多
Raft

《Raft-分布式共识算法》

一、背景在分布式系统中,一致性算法至关重要。在所有一致性算法中,Paxos最负盛名,它由莱斯利·兰伯特(Leslie Lamport)于1990年提出,是一种基于消息传递的一致性算法,被认为是类似算法中最有效的。 Paxos算法虽然很有效,但复杂的原理使它实现起来非常困难,截止目前,实现Paxos算法的开源软件很少,比较出名的有Chubby、LibPaxos。此外,Zookeeper采用的 ZAB(Zookeeper Atomic Broadcast)协议也是基于Paxos算法实现的,不过ZAB对Paxos进行了很多改进与优化,两者的设计目标也存在差异——ZAB协议主要用于构建一个高可用的分布式数据主备系统,而Paxos 算法则是用于构建一个分布式的一致性状态机系统。 由于Paxos算法过于复杂、实..

更多
loading..
MySQL

MySQL DateTime和Timestamp时区问题

一、背景最近负责一个数据传输的项目,其中一个需求就是能把一个DB里面的数据拉出来 ,然后回放到另外一个同构的DB。两个DB的服务不在一个时区(其实这不是重点),可能配置不同。之前有过类似的项目,当时是基建的同事负责做数据同步,同步过去以后DateTime、Timestamp字段的时区信息都丢了。老板让我调研下问题根因,不要踩之前的坑。 最早的时候看了下同事写的当时MySQL时区信息丢失的问题总结文档,文档里面当时把DateTime和Timestamp两个时区问题混为一起了,也没分析本质原因,导致我当时没看太明白,然后的武断的认为,之所以时区丢失了,是因为基础组件同步DateTime和Timestamp的时候同步的是字符串,比如2021-11-27 10:49:35.857969这种信息,我们传输的时候..

更多
DataStructure

遍历二叉树的几种思路

一、背景最近在公司面试(一面、二面)候选人的时候,大多数候选人基本都能正确的写出非递归版的前序遍历和中序遍历二叉树,但是大多数人都不能正确的写出非递归版的后续遍历。跟一个曾经拿过NOI银牌同事私下讨论了下后续遍历算法到底难不难。结论是,说难也难说不难也不难,说不难是因为,如果你看过相关解法,你可以很快就就理解解法的思路。说难,是如果你没看过,或者看了过了很久又忘了,要在15分钟左右写个Bug free的版本还是有点难的。 跟同事讨论下二叉树遍历的几种写法,所以就有了这篇文章。 二、二叉树几种解法的思考2.1 递归版前序遍历递归 func preOrderRecursion(node *TreeNode, ans *[]int) { if node == nil { return ..

更多
Book

《黑客与画家》

摘录与 《黑客与画家》 第一章节:为什么书呆子不受欢迎首先这里“书呆子”指的“高智商”的人。 解开这个谜的关键是把问题换一种提法。为什么聪明的小孩没有让自己变得受欢迎?如果他们真的很聪明,为什么找不到受欢迎的诀窍呢?他们在标准化测试中表现得这么好,为什么就不能在这方面也大获成功呢? 有一种观点认为,其他小孩妒忌聪明学生,所以聪明的学生不可能受到欢迎。我倒希望这种解释是对的。回想起来,要是初中里真的有人妒忌我,那么他们一定费了很大力气才把这种妒忌隐藏得无法发现。而且,在任何情况下,如果聪明真的令他人妒忌,这反而会招来女生。因为女生喜欢被其他男生妒忌的男生。 在我就读过的学校,聪明根本就是无足轻重的一样东西。同学们既不看重它,也不唾弃它。如果别的事情都相同,那么大家还是愿意自己变得聪明一点,因为这总比做个笨..

更多
Book

《清醒思考的艺术》

摘录与 《清醒思考的艺术》 1. 幸存偏误为什么你该去逛逛墓地 幸存偏误是指:由于日常生活中更容易看到成功、看不到失败,你会系统性地高估成功的希望。不了解现实的你(与雷托一样)对成功抱有一种幻想,认识不到成功的概率有多微弱。每位成功的作家背后都有100个作品卖不出去的作家,每个作品卖不出去的作家背后又有100个找不到出版社的作者,每个找不到出版社的作者背后又有数百个抽屉里沉睡着刚动笔的手稿的写作爱好者。而我们总是听到成功者的故事,认识不到作家的成功概率有多小。摄影师、企业家、艺术家、运动员、建筑师、诺贝尔奖得主、电视制作人和选美冠军的情况也是一样。媒体没兴趣去刨挖失败者的墓地,这事也不归他们负责。这意味着:要想缓解幸存偏误,你就得了解这些。 幸存偏误意味着:你系统性地高估了成功概率。解决办法:尽可能常..

更多
Book

《被讨厌的勇气》

摘录与 《被讨厌的勇气》 引言提出论点:“人可以改变,而且人人都可以获得幸福。” 青年:世界是简单的,人生也是如此。假若这种命题中含有几分真理,那也是对于孩子的世界而言。孩子的世界没有劳动或纳税之类的现实义务,他们每天都在父母或社会的呵护下自由自在地生活,未来充满无限希望,自己也似乎无所不能。孩子们的眼睛被遮盖了,不必去面对丑恶的现实。的确,孩子眼中的世界呈现出简单的姿态。 但是,随着年龄的增长,世界便逐渐露出真面目。人们不得不接受“我只不过如此”之类的现实,原以为等候在人生路上的一切“可能”都会变成“不可能”。幸福的浪漫主义季节转瞬即逝,残酷的现实主义时代终将到来。 人一旦长大,就会被复杂的人际关系所困扰,被诸多的责任所牵绊。工作、家庭或者社会责任,一切都是。当然,孩提时代无法理解的歧视、战争或阶级之..

更多
LinearAlgebra

MIT - 线性代数

一、Lesson 11.1 方程组的几何解释 上面方程组我们可以写成矩阵形式 上面的矩阵可以看成 Ax = b的形式 : 系数矩阵(A):将方程系数按行提取出来,构成一个矩阵 未知向量(x):将方程未知数提取出来,按列构成一个向量。 向量(b) :将等号右侧结果按列提取,构成一个向量 1.1.1 行图像在坐标系上画出“行图像”,可以知两个线交点就是我们要求的解 1.1.2 列图像从列图像的角度,我们再求这个方程可以看成矩阵: 1.2 方程组的几何形式推广1.2.1 高维行图像我们将方程维数推广,从三维开始,如果我们继续做行图像求解,那么会的到一个很复杂的图像。 矩阵如下: 如果绘制行图像,很明显这是一个三个平面相交得到一点,我们想直接看出 这个点的性质可谓是难上加难,比较靠谱的思路是先联..

更多
Envoy

Envoy 编译调试

Debian9 上编译调试主要参考Envoy官方的Bazel编译文档 下载bazelisk-linux-amd64 sudo wget -O /usr/local/bin/bazel https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-amd64 sudo chmod +x /usr/local/bin/bazel 安装依赖 sudo apt-get install \ autoconf \ automake \ cmake \ curl \ libtool \ make \ ninja-build \ patch \ ..

更多
BookETCD

《ETCD实战》

摘录与 《ETCD实战》 背景ectd 常见问题 etcd 基础 etcd 实践 etcd v2 功能 etcd v2 存在的问题 第一,etcd v2 不支持范围查询和分页。分页对于数据较多的场景是必不可少的。在 Kubernetes 中,在集群规模增大后,Pod、Event 等资源可能会出现数千个以上,但是 etcd v2 不支持分页,不支持范围查询,大包等 expensive request 会导致严重的性能乃至雪崩问题。 第二,etcd v2 不支持多 key 事务。在实际转账等业务场景中,往往我们需要在一个事务中同时更新多个 key。 然后是 Watch 机制可靠性问题。Kubernetes 项目严重依赖 etcd Watch 机制,然而 etcd v2 是内存型、不支持保存 key 历史版本的..

更多
Book

《设计模式之美》

摘录与 《设计模式之美》 前言什么是设计模式设计模式讲的是如何写出可扩展、可读、可维护的高质量代码,所以,它们跟平时的编码会有直接的关系,也会直接影响到你的开发能力。 为什么要学习设计模式 应对面试中的设计模式相关问题。学习设计模式和算法一样,最功利、最直接的目的,可能就是应对面试了。 告别写被人吐槽的烂代码,代码能力是一个程序员最基础的能力,是基本功,是展示一个程序员基础素养的最直接的衡量标准。你写的代码,实际上就是你名片。我见过太多的烂代码,比如命名不规范、类设计不合理、分层不清晰、没有模块化概念、代码结构混乱、高度耦合等等。这样的代码维护起来非常费劲,添加或者修改一个功能,常常会牵一发而动全身,让你无从下手,恨不得将全部的代码删掉重写!当然,在这些年的工作经历中,我也看到过很多让我眼前一亮的代码。每当..

更多
Book

《Clean Code》

摘录与 《代码整洁之道》 什么是整洁代码 能通过所有测试; 没有重复代码; 体现系统中的全部设计理念; 包括尽量少的实体,比如类、方法、函数等。 童子军军规光把代码写好可不够。必须时时保持代码整洁。我们都见过代码随时间流逝而腐坏。我们应当更积极地阻止腐坏的发生。 让营地比你来时更干净。 有意义的命名名副其实名副其实说起来简单。我们想要强调,这事很严肃。选个好名字要花时间,但省下来的时间比花掉的多。注意命名,而且一旦发现有更好的名称,就换掉旧的。这么做,读你代码的人(包括你自己)都会更开心。 变量、函数或类的名称应该已经答复了所有的大问题。它该告诉你,它为什么会存在,它做什么事,应该怎么用。如果名称需要注释来补充,那就不算是名副其实。 避免误导程序员必须避免留下掩藏代码本意的错误线索。应当避免使用与本意相悖..

更多
Book

《30天自制操作系统》

30天自制操作系统启动区(boot sector)软盘第一个的扇区称为启动区。那么什么是扇区呢?计算机读写软盘的时候,并不是一个字节一个字节地读写的,而是以512字节为一个单位进行读写。因此,软盘的512字节就称为一个扇区。一张软盘的空间共有1440KB,也就是1474560字节,除以512得2880,这也就是说一张软盘共有2880个扇区。那为什么第一个扇区称为启动区呢?那是因为计算机首先从最初一个扇区开始读软盘,然后去检查这个扇区最后2个字节的内容。如果这最后2个字节不是0x55 AA,计算机会认为这张盘上没有所需的启动程序,就会报一个不能启动的错误。(也许有人会问为什么一定是0x55 AA呢?那是当初的设计者随便定的,笔者也没法解释)。如果计算机确认了第一个扇区的最后两个字节正好是0x55 AA,那它就..

更多
Book

《Clean Architecture》

零、概述软件架构设计是一件非常困难的事情,这通常需要大多数程序员所不具备的经验和技能。同时,也不是所有人都愿意花时间来学习和钻研这个方向。做一个好的软件架构师所需要的自律和专注程度可能会让大部分程序员始料未及,更别提软件架构师这个职业本身的社会认同感与人们投身其中的热情了。 采用好的软件架构可以大大节省软件项目构建与维护的人力成本。让每次变更都短小简单,易于实施,并且避免缺陷,用最小的成本,最大程度地满足功能性和灵活性的要求。 0.1 设计与架构究竟是什么?一直以来,设计(Design)与架构(Architecture)这两个概念让大多数人十分迷惑——什么是设计?什么是架构?二者究竟有什么区别? 本书的一个重要目标就是要清晰、明确地对二者进行定义。首先我要明确地说,二者没有任何区别。一丁点区别都没有! “架..

更多
BookRedis

《Redis核心技术与实战》

数据结构Redis数据结构简单来说,底层数据结构一共有 6 种,分别是简单动态字符串、双向链表、压缩列表、哈希表、跳表和整数数组。它们和数据类型的对应关系如下图所示: 全局哈希表 因为这个哈希表保存了所有的键值对,所以,我也把它称为全局哈希表。哈希表的最大好处很明显,就是让我们可以用 O(1) 的时间复杂度来快速查找到键值对——我们只需要计算键的哈希值,就可以知道它所对应的哈希桶位置,然后就可以访问相应的 entry 元素。 渐进式 rehash简单来说就是在第二步拷贝数据时,Redis 仍然正常处理客户端请求,每处理一个请求时,从哈希表 1 中的第一个索引位置开始,顺带着将这个索引位置上的所有 entries 拷贝到哈希表 2 中;等处理下一个请求时,再顺带拷贝哈希表 1 中的下一个索引位置的 entr..

更多
Eng-Practices

DDD-领域驱动设计

一、DDD的基础概念1.1 什么是 DDD 2004 年埃里克·埃文斯(Eric Evans)发表了《领域驱动设计》(Domain-Driven Design –Tackling Complexity in the Heart of Software)这本书,从此领域驱动设计(Domain Driven Design,简称 DDD)诞生。DDD 核心思想是通过领域驱动设计方法定义领域模型,从而确定业务和应用边界,保证业务模型与代码模型的一致性。领域驱动设计,主要是用来指导如何解耦业务系统,划分业务模块,定义业务领域模型及其交互。领域驱动设计这个概念并不新颖,早在 2004 年就被提出了,到现在已经有十几年的历史了。不过,它被大众熟知,还是基于另一个概念的兴起,那就是微服务。不过,我个人觉得,领域驱动设计有点..

更多
Book

《数据密集型应用系统设计》

数据密集型应用(data-intensive applications)正在通过使用这些技术进步来推动可能性的 边界。一个应用被称为数据密集型的,如果数据是其主要挑战(数据量,数据复杂度或数据变化速度)—— 与之相对的是计算密集型,即处理器速度是其瓶颈。 数据系统的基石可靠性、可扩展性、可维护性现今很多应用程序都是数据密集型(data-intensive)的,而非计算密集型(compute-intensive)的。因此CPU很少成为这类应用的瓶颈,更大的问题通常来自数据量、数据复杂性、以及数据的变更速度。 可靠性(Reliability)系统在困境(adversity)(硬件故障、软件故障、人为错误)中仍可正常工作(正确完成功 能,并能达到期望的性能水准)。 人们对于一个东西是否可靠,都有一个直观的想法。人..

更多
Book

《从0开始学架构》

架构设计理念架构设计理念,可以提炼为下面几个关键点: 架构是系统的顶层结构。 架构设计的主要目的是为了解决软件系统复杂度带来的问题。 架构设计需要遵循三个主要原则:合适原则、简单原则、演化原则。 架构设计首先要掌握业界已经成熟的各种架构模式,然后再进行优化、调整、创新。 框架设计需要考的因素/影响架构复杂性的几个因素 高性能, 衡量软件性能包括了响应时间、TPS、服务器资源利用率等客观指标,也可以是用户的主观感受。 高可用,高可用性就是技术实力的象征,高可用性就是竞争力。99.99%(俗称4个9)网站不可用时间=52.56分钟 可扩展性,设计具备良好可扩展性的系统,有两个基本条件:“正确预测变化、完美封装变化”。 低成本,语言选择、方案选择。 安全,功能安全XSS、CSRF等,架构安全、访问策略。 规模..

更多
BookLinux

《Linux内核技术实战》

Page Cache什么是 Page Cache? 通过这张图片你可以清楚地看到,红色的地方就是 Page Cache,很明显,Page Cache 是内核管理的内存,也就是说,它属于内核不属于用户。 $ cat /proc/meminfo ... Buffers: 1224 kB Cached: 111472 kB SwapCached: 36364 kB Active: 6224232 kB Inactive: 979432 kB Active(anon): 6173036 kB Inactive(anon): 927932 kB Active(file): 51196 kB Inactive(..

更多
BookLinux

《Linux性能优化实战》

CPU性能篇uptime 什么是平均负载?简单来说,平均负载是指单位时间内,系统处于可运行状态和不可中断状态的平均进程数,也就是平均活跃进程数,它和 CPU 使用率并没有直接关系。这里我先解释下,可运行状态和不可中断状态这俩词儿。 所谓可运行状态的进程,是指正在使用 CPU 或者正在等待 CPU 的进程,也就是我们常用 ps 命令看到的,处于 R 状态(Running 或 Runnable)的进程。 不可中断状态的进程则是正处于内核态关键流程中的进程,并且这些流程是不可打断的,比如最常见的是等待硬件设备的 I/O 响应,也就是我们在 ps 命令中看到的 D 状态(Uninterruptible Sleep,也称为 Disk Sleep)的进程。 比如,当一个进程向磁盘读写数据时,为了保证数据的一致性,在得到..

更多
Book

《趣谈网络协议》

通信协议综述IP && MACIP 地址是一个网卡在网络世界的通讯地址,相当于我们现实世界的门牌号码。既然是门牌号码,不能大家都一样,不然就会起冲突。比方说,假如大家都叫六单元 1001 号,那快递就找不到地方了。所以,有时候咱们的电脑弹出网络地址冲突,出现上不去网的情况,多半是 IP 地址冲突了。 下面这个表格,详细地展示了 A、B、C 三类地址所能包含的主机的数量。在后文中,我也会多次借助这个表格来讲解。 无类型域间选路(CIDR) 于是有了一个折中的方式叫作无类型域间选路,简称 CIDR。这种方式打破了原来设计的几类地址的做法,将 32 位的 IP 地址一分为二,前面是网络号,后面是主机号。从哪里分呢?你如果注意观察的话可以看到,10.100.122.2/24,这个 IP 地址中有..

更多
BookMySQL

《MySQL实战45讲》

binlog && redo log什么是 binlog binlog 是逻辑日志,记录的是这个语句的原始逻辑/变化,比如“给 ID=2 这一行的 c 字段加 1 ”。 binlog 是追加写,不会覆盖之前的数据,可以提供完整的数据归档的能力。 什么是 redo log redo log 是物理日志,记录的是“在某个数据页上做了什么修改”; redo log 提供 crash-safe 能力。 一般只有4G ,4个文件,循环复写。 binlog 和 redo log 不同点因为最开始 MySQL 里并没有 InnoDB 引擎。MySQL 自带的引擎是 MyISAM,但是 MyISAM 没有 crash-safe 的能力,binlog 日志只能用于归档。而 InnoDB 是另一个公司以插..

更多
Book

《深入浅出计算机组成原理》

基础篇计算机的基本硬件组成 第一,广。组成原理中的概念非常多,每个概念的信息量也非常大。比如想要理解 CPU 中的算术逻辑单元(也就是 ALU)是怎么实现加法的,需要牵涉到如何把整数表示成二进制,还需要了解这些表示背后的电路、逻辑门、CPU 时钟、触发器等知识。 第二,深。组成原理中的很多概念,阐述开来就是计算机学科的另外一门核心课程。比如,计算机的指令是怎么从你写的 C、Java 这样的高级语言,变成计算机可以执行的机器码的?如果我们展开并深入讲解这个问题,就会变成《编译原理》这样一门核心课程。 第三,学不能致用。学东西是要拿来用的,但因为这门课本身的属性,很多人在学习时,常常沉溺于概念和理论中,无法和自己日常的开发工作联系起来,以此来解决工作中遇到的问题,所以,学习往往没有成就感,就很难有动力坚持下去。..

更多
BookChip

《说透芯片》

基础知识晶体管想了解晶体管,你得先了解它的“前身”——电子管。电子管是中文翻译后的名称,英文原文其实是真空管。从这个名字,你可以想象,它其实是把参与工作的金属薄片,也就是电极,封装在一个真空的容器内,真空容器一般指的是玻璃瓶。 整个电子行业,并不是从芯片开始的,而是从电子管开始。电子管最鼎盛时期的代表作,就是世界上的第一台电子计算机。这台 1946 年诞生的电子计算机,占地 150 平方米,重达 30 吨,里面的电路使用了 17468 只电子管、7200 只电阻、10000 只电容、50 万条线。 这台计算机虽然运算速度不快,但基本具备了现代计算机的主要结构和功能,这也是电子管能达到的最高成就了。其实从上图你也可以看出来,电子管最大的缺点就是,真空容器对于电子产品来说体积太大了。 如果人类停留在电子管技术上..

更多
Golang

Golang RWMutext 代码走读

type RWMutex struct { w Mutex // held if there are pending writers writerSem uint32 // 写的信号量 readerSem uint32 // 读的信号量 readerCount int32 // 等待写的个数 readerWait int32 // 等待读的个数 } // 加“读锁” // 对readerCount + 1 。 // 然后看 readerCount是不是小于0 // 小于0表示 正在加写锁,然后阻塞到rw.readerSem 这个信号上。 func (rw *RWMutex) RLock() { if atomic.AddInt32(..

更多
Sort

常用的排序算法

插入排序func insertSort(nums []int) { for i := 1; i < len(nums); i++ { tmp := nums[i] for j := i; j >= 0; j-- { if j > 0 && tmp < nums[j-1] { nums[j] = nums[j-1] } else { nums[j] = tmp break } } } } 折半插入排序func binaryInsertSor..

更多
Redis

Redis 高可用解决方案总结

一、主从复制什么是主从复制我们正常在项目中对redis进行应用,一般都不会是单点的。因为,单点的宕机即不可用,不能保证可用性。另外,单点redis读写指令都会打到同一个服务里面,也会影响性能。在通常的应用中,对redis的读操作远远多于写操作,所以,我们一般会选择“一主多从”的集群策略。 主中的数据有两个副本(replication)即从redis1和从redis2,即使一台服务器宕机其它两台服务也可以继续提供服务。 主中的数据和从上的数据保持实时同步,当主写入数据时通过主从复制机制会复制到两个从服务上。 只有一个主redis,可以有多个从 redis。 主从复制不会阻塞master,在同步数据时,master可以继续处理client请求。 一个可以即是主又是从,如下图: 主从复制过程一般当slav..

更多
Redis

Redis 源码分析(七) :skiplist

一、skiplist由来skiplist本质上也是一种查找结构,用于解决算法中的查找问题(Searching),即根据给定的key,快速查到它所在的位置(或者对应的value)。 我们在《Redis内部数据结构详解》系列的第一篇中介绍dict的时候,曾经讨论过:一般查找问题的解法分为两个大类:一个是基于各种平衡树,一个是基于哈希表。但skiplist却比较特殊,它没法归属到这两大类里面。 这种数据结构是由William Pugh发明的,最早出现于他在1990年发表的论文《Skip Lists: A Probabilistic Alternative to Balanced Trees》。对细节感兴趣的同学可以下载论文原文来阅读。 skiplist,顾名思义,首先它是一个list。实际上,它是在有序链表的基础..

更多
Redis

Redis 源码分析(六) :quciklist

一、什么是quicklist由于考虑到链表adlist的附加空间相对太高,prev和next指针就要占去 16 个字节 (64bit系统的指针是8个字节),另外每个节点的内存都是单独分配,会加剧内存的碎片化,影响内存管理效率。 quicklist是一个3.2版本之后新增的基础数据结构,是redis自定义的一种复杂数据结构,将ziplist和adlist结合到了一个数据结构中。主要是作为list的基础数据结构。在3.2之前,list是根据元素数量的多少采用ziplist或者adlist作为基础数据结构,3.2之后统一改用quicklist,从数据结构的角度来说quicklist结合了两种数据结构的优缺点,复杂但是实用: 链表在插入,删除节点的时间复杂度很低;但是内存利用率低,且由于内存不连续容易产生内存碎片..

更多
Redis

Redis 源码分析(五) :ziplist

一、前言ziplist是redis节省内存的典型例子之一,这个数据结构通过特殊的编码方式将数据存储在连续的内存中。在3.2之前是list的基础数据结构之一,在3.2之后被quicklist替代。但是仍然是zset底层实现之一。 二、存储结构压缩表没有数据结构代码定义,完全是通过内存的特殊编码方式实现的一种紧凑存储数据结构。我们可以通过ziplist的初始化函数和操作api来倒推其内存分布。 #define ZIP_END 255 #define ZIPLIST_BYTES(zl) (*((uint32_t*)(zl))) // 获取ziplist的bytes指针 #define ZIPLIST_TAIL_OFFSET(zl) (*((uint32_t*)((zl)+sizeof(uint..

更多
Redis

Redis 源码分析(四) :intset

一、什么是intsetintset是Redis内存数据结构之一,用来实现Redis的Set结构(当集合元素不大于设定值并且元素都是整数时,就会用intset作为set的底层数据结构),它的特点有: 元素类型只能为数字。 元素有三种类型:int16_t、int32_t、int64_t。 元素有序,不可重复。 intset和sds一样,内存连续,就像数组一样。 二、数据结构定义typedef struct intset { uint32_t encoding; // 编码类型 int16_t、int32_t、int64_t uint32_t length; // 长度 最大长度:2^32 int8_t contents[]; // 柔性数组 } intset; enco..

更多
Redis

Redis 源码分析(三) :dict

一、什么是dictdict (dictionary 字典),通常的存储结构是Key-Value形式的,通过Hash函数对key求Hash值来确定Value的位置,因此也叫Hash表,是一种用来解决算法中查找问题的数据结构,默认的算法复杂度接近O(1),Redis本身也叫Remote Dictionary Server(远程字典服务器),其实也就是一个大字典,它的key通常来说是String类型的,但是Value可以是String、Set、ZSet、Hash、List等不同的类型,下面我们看下dict的数据结构定义。 二、Redis Dict数据结构 从上图可以看出与dict相关的关键数据结构有三个,分别是: dict是Redis中的字典结构,包含两个dictht。 dictht表示一个Hash表。 dic..

更多
Redis

Redis 源码分析(二) :ADList

概述ADList(A generic doubly linked list)是 redis 自定义的一种双向链表,广泛运用于 redisClients 、 redisServer 、发布订阅、慢查询、监视器等。(注:3.0及以前还会被运用于list结构中,在3.2以后被quicklist取代)。 链表提供了高效的节点重排能力,以及顺序性的节点访问方式,并且可以通过增删节点来灵活地调整链表的长度。 链表在Redis 中的应用非常广泛,比如列表键的底层实现之一就是链表。当一个列表键包含了数量较多的元素,又或者列表中包含的元素都是比较长的字符串时,Redis 就会使用链表作为列表键的底层实现。 链表结构是 Redis 中一个常用的结构,它可以存储多个字符串 它是有序的 能够存储2的32次方减一个节点(超过 40..

更多
Redis

Redis 源码分析(一) :sds

什么是sds字符串是Redis中最为常见的数据存储类型,其底层实现是简单动态字符串sds(simple dynamic string),是可以修改的字符串。 它类似于Java中的ArrayList,它采用预分配冗余空间的方式来减少内存的频繁分配。 数据结构// 3.0及以前 struct sdshdr { // 记录buf数组中已使用字节数量 unsigned int len; // 记录buf数组中未使用的字节数量 unsigned int free; // 字节数组,存储字符串 char buf[]; }; // >=3.2 struct __attribute__ ((__packed__)) sdshdr5 { unsigned cha..

更多
MySQL

MySQL 索引那些事

1. MySQL 常见几种索引类型1.1 普通索引,是最基本的索引,它没有任何限制。它有以下几种创建方式: (1)直接创建索引 CREATE INDEX index_name ON table(column(length)) (2)修改表结构的方式添加索引 ALTER TABLE table_name ADD INDEX index_name ON (column(length)) (3)创建表的时候同时创建索引 CREATE TABLE `table` ( `id` int(11) NOT NULL AUTO_INCREMENT , `title` char(255) CHARACTER NOT NULL , `conten..

更多
LinuxMemory

内存管理、寻址方式那些事

一、内存1.1 什么是内存  简单地说,内存就是一个数据货架。内存有一个最小的存储单位,大多数都是一个字节。内存用内存地址(memory address)来为每个字节的数据顺序编号。因此,内存地址说明了数据在内存中的位置。内存地址从0开始,每次增加1。这种线性增加的存储器地址称为线性地址(linear address)。   内存地址的编号有上限。地址空间的范围和地址总线(address bus)的位数直接相关。CPU通过地址总线来向内存说明想要存取数据的地址。以英特尔32位的80386型CPU为例,这款CPU有32个针脚可以传输地址信息。每个针脚对应了一位。如果针脚上是高电压,那么这一位是1。如果是低电压,那么这一位是0。32位的电压高低信息通过地址总线传到内存的32个针脚,内存就能把电压高低信息转换成3..

更多
DataStructure

B-Tree、B+Tree、B*Tree

一、B-Tree1.1 什么是B-Tree 1970年,R.Bayer和E.mccreight提出了一种适用于外查找的树,它是一种平衡的多叉树,称为B树,其定义如下 根结点至少有两个子女。 每个中间节点都包含k-1个元素和k个孩子,其中 m/2 <= k <= m 每一个叶子节点都包含k-1个元素,其中 m/2 <= k <= m 所有的叶子结点都位于同一层。 每个节点中的元素从小到大排列,节点当中k-1个元素正好是k个孩子包含的元素的值域分划。 M = 3 1.2 B-Tree 查找假设我们要查找的数据是 5 二、B+Tree2.1 什么是B+TreeB+ 树是一种树数据结构,是一个n叉树,每个节点通常有多个孩子,一棵B+树包含根节点、内部节点和叶子节点。根节点可..

更多
MySQL

MyISAM和InnoDB区别和应用场景

什么是MyISAM 和InnoDB MyISAM是MySQL的默认数据库引擎(5.5版之前),由早期的ISAM所改良。虽然性能极佳,但却有一个缺点:不支持事务处理(transaction)。 InnoDB,是MySQL的数据库引擎之一,为MySQL AB发行binary的标准之一。InnoDB由Innobase Oy公司所开发,2006年五月时由甲骨文公司并购。与传统的ISAM与MyISAM相比,InnoDB的最大特色就是支持了ACID兼容的事务(Transaction)功能,类似于PostgreSQL。 MyISAM:它是基于传统的ISAM类型,ISAM是Indexed Sequential Access Method (有索引的顺序访问方法) 的缩写,它是存储记录和文件的标准方法。不是事务安全的,而且..

更多
Golang

Golang 内存对齐问题

什么是内存对齐?CPU把内存当成是一块一块的,块的大小可以是2,4,8,16字节大小,因此CPU在读取内存时是一块一块进行读取的。块大小成为memory access granularity(粒度)。 假设CPU访问粒度是4,也就是一次性可以读取内存中的四个字节内容;当我们不采用内存对齐策略,如果需要访问A中的b元素,CPU需要先取出0-3四个字节的内容,发现没有读取完,还需要再次读取,一共需要进行两次访问内存的操作;而有了内存对齐,参考左图,可一次性取出4-7四个字节的元素也即是b,这样就只需要进行一次访问内存的操作。所以操作系统这样做的原因也就是所谓的拿空间换时间,提高效率。 为什么要内存对齐?会了关于结构体内存大小的计算,可是为什么系统要对于结构体数据进行内存对齐呢,很明显所占用的空间大小要更多。原..

更多
Consul

服务发现之Consul

consul是一个可以提供服务发现,健康检查,多数据中心,Key/Value存储等功能的分布式服务框架 用于实现分布式系统的服务发现与配置。与其他分布式服务注册与发现的方案,Consul的方案更”一站式”,内置了服务注册与发现框架、分布一致性协议实现、健康检查、Key/Value存储、多数据中心方案,不再需要依赖其他工具(比如ZooKeeper等)。使用起来也较为简单。Consul用Golang实现,因此具有天然可移植性(支持Linux、Windows和Mac OS X);安装包仅包含一个可执行文件,方便部署,与Docker等轻量级容器可无缝配合。 Consul 的使用场景 docker 实例的注册与配置共享 coreos 实例的注册与配置共享 vitess 集群 SaaS 应用的配置共享 与 confd ..

更多
Idgen

分布式id几种生成方案

一、UUIDUUID 是 通用唯一识别码(Universally Unique Identifier)的缩写,是一种软件建构的标准,亦为开放软件基金会组织在分布式计算环境领域的一部分。其目的,是让分布式系统中的所有元素,都能有唯一的辨识信息,而不需要通过中央控制端来做辨识信息的指定。如此一来,每个人都可以创建不与其它人冲突的UUID。在这样的情况下,就不需考虑数据库创建时的名称重复问题。目前最广泛应用的UUID,是微软公司的全局唯一标识符(GUID),而其他重要的应用,则有Linux ext2/ext3文件系统、LUKS加密分区、GNOME、KDE、Mac OS X等等。另外我们也可以在e2fsprogs包中的UUID库找到实现。 UUID的标准形式包含32个16进制数字,以连字号分为五段,形式为8-4-4..

更多
GolangLua

Go 执行Lua脚本和JS脚本测试

最近有个需求需要在Go项目里面执行动态脚本,github上有好几个lua执行解释器,但是有很多要不就很久没维护了,要不就没有什么文档,经过几个对比我最后用的是 https://github.com/yuin/gopher-lua。JS解析器用的github.com/robertkrimen/otto。 具体测试代码如下,给有需求的朋友参考。 github地址 package main import ( "fmt" "github.com/robertkrimen/otto" "github.com/yuin/gluamapper" "github.com/yuin/gopher-lua" "time" ) //function add(a, b) //return..

更多
HTPPProtobufNet

测试Protobuf在Http传输测试

Demo:https://github.com/fanlv/ProtobufOnHttpGo 一、编写Proto文件syntax = "proto3"; // 生成go代码 //protoc --go_out=. user.proto // 生成oc代码 //protoc --objc_out=. user.proto package user; message LoginRequest { string username = 1; string password = 2; } message BaseResponse{ int64 code = 1; string msg = 2; } message User{ string uid = 1; string..

更多
DataStructure

二叉树、2-3 树、红黑树

有序数组的优势在于二分查找,链表的优势在于数据项的插入和数据项的删除。但是在有序数组中插入数据就会很慢,同样在链表中查找数据项效率就很低。综合以上情况,二叉树可以利用链表和有序数组的优势,同时可以合并有序数组和链表的优势,二叉树也是一种常用的数据结构。 一、满二叉树一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为 K,且结点总数是(2^k) -1 ,则它就是满二叉树。 二、完全二叉树若设二叉树的深度为 h,除第 h 层外,其它各层 (1 ~ h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。 三、二叉查找树二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树..

更多
IO

高并发服务器IO模型

服务端IO模型总结 草稿 网络框架视角零、Nginx 一、Netty(主从Reactor)MainReactor负责客户端的连接请求,并将请求转交给SubReactor SubReactor负责相应通道的IO读写请求 非IO请求(具体逻辑处理)的任务则会直接写入队列,等待worker threads进行处理 二、GRPC-GO (Goroutine Per Connection)net.Listen -> Serve() -> lis.Accept() net库的accept -> 一个连接开个一个goroutine -> s.handleRawConn(rawConn) -> newHTTP2Transport(conn, authInfo) -> newH..

更多
iOSGRPC

iOS之GRPC 测试(附代码)

背景最近在用gRPC框架测试,想起去年调研Protocol Buffer在HTTP的时候传输,了解过这个框架,当时没深入。这次做gRPC服务器端,随便看下iOS这边实现方式,附上测试代码。 demo地址: https://github.com/fanlv/gRPCDemo proto文件package user; message LoginRequest { string username = 1; string password = 2; } message BaseResponse{ int64 code = 1; string msg = 2; } message User{ string uid = 1; string name = 2; string ..

更多
GolangHTTP

跨域请求的几种解决方案

需求背景最近做的Apigate优化,前端的同学要求能在配置后台页面上加上一键测试接口的功能,但是由于浏览器的同源策略防止跨域攻击,所以前端的页面默认是不能请求其他域名的接口。 方案一 Nginx配置代理location /proxy { if ($arg_url) { proxy_pass $arg_url?; } } 最开始为了简单就配置了一个简单的代理,通过url传入想要访问的接口例如: http://nginxserver/proxy?url=http://10.23.39.140:8080/app/list 这样前端需要什么测试什么接口只需要通过url传过来,Nginx会方向代理到对应的url上返回结果。 但是这个方法有个问题,url中的地址支持IP访问,不支持域名的..

更多
Probability

概率论基础

样本空间与事件A⊂B 事件 B 包含了事件 A,A 被包含于 B A∩B A 与 B 的交集,表示事件 A 和事件 B 同时发生 A∪B A 与 B 的并集,表示事件 A 或事件 B 或他们二者同事发生 P(A|B) 在事件 B 发生下,事件 A 发生的概率 对偶公式 随机事件运算(1)交换律:A∪B=B∪A、AB=BA (2)结合律:( A∪B )∪C=A∪( B∪C ) (3)分配律:A∪( BC )=( A∪B )( A∪C )A( B∪C )=( AB )∪( AC ) (4)摩根律:A B=A∪B、A ∪ B=A B 概率的三个基本性质 二项系数 蒙特卡罗(Monte Carlo) 乘法公式P(AB)=P(B)P(A|B) = P(A)P(B|A) 全概率公式 贝叶斯公式(Bayes)

更多
Calculus

微积分基础

导数(Derivatives) 导数是函数的局部性质。一个函数在某一点的导数描述了这个函数在这一点附近的变化率。如果函数的自变量和取值都是实数的话,函数在某一点的导数就是该函数所代表的曲线在这一点上的切线斜率。导数的本质是通过极限的概念对函数进行局部的线性逼近。例如在运动学中,物体的位移对于时间的导数就是物体的瞬时速度。 一阶导数为 0 的时候,对应的值不是最大值(局部)就是最小值(局部)。 求导规则加(减)法则:(f+g)'=f'+g' 乘法法则:(f*g)'=f'*g+g'*f 除法法则:(f/g)'=(f'*g-g'*f)/g^2 y = x^n => dy/dx = nx^n-1 y = sin(x) => dy/dx = cos(x) y = e^x => dy/dx = e^..

更多
Statistics

统计学基础

最近休息在家无聊,整理下之前看的统计学的一些基础知识,方便以后查阅吧。 基础名词 均值 (Mean),所有数相加出去数量。 中位数 (Median), 中间一个数,或者是中间的两个数相加除以 2 众数 (Mode),出现次数最多的数。 极差 (Range),最大值减去最小值(Max-Min) 中程数(Mid-Range) (Max+Min)/ 2 样本 (sameple) 总体 (population) 总体的均值 (mean of a population) 𝝻./ 样本的均值 (mean of a sameple) 总体方差 (variance of a population) 样本方差(Sample variance) 基础概念和公式基础概念对应的数学符号: 总体均值(Population Mea..

更多
HTTP

深入浅出HTTP

深入浅出HTTP一、什么是Http和TCP HTTP(HyperText Transfer Protocol)超文本传输协议,是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。1960年美国人Ted Nelson构思了一种通过计算机处理文本信息的方法,并称之为超文本(hypertext),这成为了HTTP超文本传输协议标准架构的发展根基。Ted Nelson组织协调万维网协会(World Wide Web Consortium)和互联网工程工作小组(Internet Engineering Task Force )共同合作研究,最终发布了一系列的RFC,其中著名的RFC 2616定义了HTTP 1.1。 TCP(T..

更多
HTTPProtobufNet

Protobuf On HTTP 技术预研 (附代码)

Protobuf 技术预研Demo地址:https://github.com/fanlv/ProtobufOnHttp Demo地址:https://github.com/fanlv/ProtobufOnHttpGo 一、背景现在客户端与服务器通讯主要通过Json来做数据交互,本次调研主要比较Protobuf项目中使用的优缺点,和可行性。 二、Protobuf说明2.1 什么是ProtobufProtocolBuffer(以下简称PB)是google 的一种数据交换的格式,它独立于语言,独立于平台。大部分IM通讯协议都是使用PB来传输。具体代表性的有支付宝、微信等App。 说白了,PB就是一种序列化协议,我们开发中想在什么场景中使用Protobuf做为数据交换的序列化协议,取决于自己的业务。 2.2 Pro..

更多
iOS

iOS Cookie 存储相关技术

iOS Cookie 存储相关技术一、什么是Cookie Cookie,有时也用其复数形式 Cookies,指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密)。定义于 RFC2109 和 2965 中的都已废弃,最新取代的规范是 RFC6265 [1] 。(可以叫做浏览器缓存)来自百度百科 说白了Cookie就是提供服务器存储相关数据到客户端的一种解决方案,服务器通过返回的Http头中告知客户端,我设置了Cookie,客户端收到请求以后,会读出Http响应的Header里面把对应的Cookie的key、value值持久化存到本地的Cookie文件,下次再请求服务器相关域名的接口中,会自动带上Cookie相关数据。当然客户端也可以主动设置、读取、删除这些C..

更多