0x67cq / blog Goto Github PK
View Code? Open in Web Editor NEWpublish some notes in issues, share my studying&thinking process
License: MIT License
publish some notes in issues, share my studying&thinking process
License: MIT License
其实对于算法和数据结构的分层拆分是属于软件工程课程的内容了,任何语言都能做到。只是因为Go的 组合+Interface比较明确的凸显了这个代码行文思路
func Perm(r *rand.Rand, n int) []int {
m := make([]int, n)
for i := 0; i < n; i++ {
j := r.Intn(i + 1)
fmt.Println("I:",i,"j:",j)
m[i] = m[j]
m[j] = i
}
return m
}
算法语言表述: 把当前列某一节点Y的值取给新加入节点X,然后维护一个0~N的递增队列,从这个递增队列里取一个最大的N赋给Y的值。
三句话总结:
io包,io.Reader/Writer是对一切需要进行输入输出虚拟概念的抽象,例如: socket, file, device, buffer , connection, custom struct等概念。
net包, net.Conn是一切虚拟connection的抽象, 例如:IPConn,TCPConn, UDPConn,UnixConn等虚拟链接 。
包只提供作为抽象依据的 逻辑操作。
最近用的比较多的是net和io包,但是陷入net包繁杂的调用和零零散散的接口和结构体的逻辑里。无法提高到设计层面上形成一个系统性的认知,所以才有了这篇文章,这篇文章是我提高自己视角的过程。
io包里对于循环读一个可读结构的实现如下:
func ReadFull(r Reader, buf []byte) (n int, err error) {
return ReadAtLeast(r, buf, len(buf))
}
// 这是io.ReadAtLeast的代码
func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error) {
305 if len(buf) < min {
306 return 0, ErrShortBuffer
307 }
308 for n < min && err == nil {
309 var nn int
310 nn, err = r.Read(buf[n:])
311 n += nn
312 }
313 if n >= min {
314 err = nil
315 } else if n > 0 && err == EOF {
316 err = ErrUnexpectedEOF
317 }
318 return
319 }
为什么需要循环读?
因为buffer大概率情况下是没办法对应到数据的大小的。无法保证一次读取预期的所有数据的,所以需要循环读到结尾。
因为上面的场景非常的普遍出现,所以io包里有一个ReadFull函数实现。
那么无论是任何结构,只要是可以被读取的结构,都需要这个循环读的步骤。这个步骤又如何进行通用化呢?这里可是有各种各样的输入输出的虚拟概念需要进行read,上面代码里r.Read
这个调用,可以通过r Reader
这个接口进行储存这些抽象的概念。
有一个很关键的认知,如果你再读代码读到一个接口,你不明白到底做了什么实现的时候,那说明这个接口的设计上出现了问题,需要对接口的方法进行注释&重命名&拆分。也就是说,接口的方法一定是你能够明白这是在做什么!读起来能做到逻辑上是通顺的。 做到逻辑和真实数据结构的彻底分离。
说完了接口的一个使用案例,再来说一下接口之下的东西。
在这里先跳转到net包来看,Reader还是一个非常底层的动作,但是一个Conn是一个形容一类概念的动作组了。这个能看的比较明显一些。
首先,net.Conn
因为接口是静态语言的动态性的体现,所以一个Conn接口,可以在runtime时实际上是各种结构体。例如,IPConn,UDPConn, TCPConn等等。这些都是具体的结构体。他们是不同协议的连接,但是都是Connection。
大致能看一下golang里都有哪些Conn,有非常的多,而且这些Conn里既有interface,还有struct。
net.PackageConn interface implement by icmp.PackageConn,ipv4.PackageConn struct
syscall.RawConn interface implement by ipv4.RawConn struct
开始的时候真的非常让我困惑。直到想明白了。interface是为了在逻辑上通顺算法所使用的容器。而go则在命名上体现了这一点。
Conn
在进行代码书写的时候,逻辑上符合Conn的结构体都会进行伸缩式命名。例如IPConn, UDPConn, TCPConn
当然也有一些同名的interface与struct。例如net,icmp,ipv4包的PackageConn。这些命名相同的接口和结构体在阅读源代码的时候会带来更多的困惑。如果不提前知道这些问题的话。
[TOC]
构建高并发的流程: 单节点单线程(顺序执行) -> 单节点多线程并发(系统级并发) -> 分布式(多节点并发)
所以关于如何做到分布式高并发的思考。也要先明白单节点的缺陷。针对这些缺陷,分布式做出的应对措施,以及又带来了哪些问题。
从起源到巅峰。跟随前人思考和技术发展的脉络。这样的学习曲线比起直接关注最发达的时候要容易很多。这种做法的唯一难点就是如何去掌握发展脉络。
有测试数据&应用场景才真的叫作高并发。不同的情况,不同的复杂度下,对于高并发的并发数的要求都是不同的,所以这里只是思考一些影响并发数的因素。并不是一篇讲述如何做到高并发的记录。
回到正题。单节点的限制在哪里?
一次请求的接受到返回
尽可能的使用所有机器资源进行处理
优点:
缺点:
优点:
缺点:
单节点的性能瓶颈:
能够依靠程序员提升效率
需要的观念:
明确cpu指令的时间级别、缓存读写一次、内存读写一次和磁盘读写一次的时间差。从这个时间差的比较里可以得到,缓存未命中和命中的差别。要能明确说出每条语句的执行时间级别!
只有有这样的意思之后,在执行一个长耗时操作等待的时候,能有意识的去增加一些短耗时任务,有效利用算力,比如会IO阻塞的语句开个goroutine去执行其他的任务。
分布式要明白的吧。还是时间级, n层架构彼此通信到最后完成一条请求的时间级
在这个基础上才说得上去优化。
在量级的前提下。
低量级一定是单机更效率
但是如果在量级提高的情况下。单机无法承担。所以在一个用户感知这个极限时间(或者业务要求时间内)的硬性要求时间之下都是为了支撑量级牺牲的时间。
有个很有趣的问题。
万兆带宽连接下,a请求b无磁盘io,b读写数据库。 这样作为模式A
然后b单机读写数据库这样作为模式B。
这两种模式差别的时间有多少?
其实就是在不读写磁盘的前提下,网卡+内存的转发耗时多少的问题了。
网关的转发,这样的反向代理。是否保持和客户端的长连接?socket不关闭的前提下,在得到了转发服务器返回的时候就可以直接写入了。其实也只有这样吧。如果关闭socket的话是没办法重新连接的。要分清tcp和http的层级。
那这样的话网关能够同时保持多少个socket连接就很关键了,就是因为这样才会有事件机制和epoll。这样可以减少打开的线程数量。节约内核tcb结构体空间。还有socket套接字一定也是占用内存空间的。哪怕像goroutine这样8k内存。一百万个gorutine也要占用8g的内存了。千万呢?而且要清楚,http1.1的情况下,单个客户端是可以发起多个请求的。哪怕每个客户端10个请求那其实也只能够支持到个位数万的层次所以http2才必须长连接吧。而且这些都只计算了goroutine的内存呢!运行时,切换保存的上下文。都没有进行计算!所以甚至都没办法服务到万的用户,
所以网关也要分地区。dns来根据地区返回不同的网关?http不管再怎么转发也还是依赖于tcp的依次连接。也就是dns来进行网关的分流。这样就不用保持长连接了。CDN?内容分发?这个只能做到静态文件的分发,动态内容还是吃瘪但是可以有效的减少对静态资源的长连接数量。
反向代理。
可以一点一点实验,比如 实现一个http转发 看是不是保持着这个tcp连接直到内容服务器返回的时候返回结果。这大概基本就是了。因为这样才叫反向代理。服务器以为自己只是在接受网关的服务!
先查这些具体的时间等级和内存消耗
还可以写服务,然后按照这个一点一点的升级,每根据一点提升一次都记录一次性能。做个对比。这一套玩下来也就成为一个合格的程序员了吧!嘿。
做到这个再去试试编译原理,数据库确实兴趣没有很大。我还是对内存级别的更感兴趣好像
以上都是基于linux内核
然后这里缺的就是操作系统以及往下的了
比如如何让内核调度更有效率,更省内存
内核级别
在往下,我不做冯诺依曼体系结构啦哈哈哈哈
甚至通信行业的通信速度。网络硬件。
goroutine是基于内核线程。所以才可以分布在不同的cpu核心里跑。内核调度的原子层面就是内核线程
线程安全的意思,应该是,任意一个方法都是原子的。不会因为线程被系统挂起或者切换导致的 数据错误,比如读出计算没来的急写入就被挂起了。后续的继续读写这块内存。关键是原子性
#k8s手动搭建步骤拆解
急急急,搞大跃进呢你?这么急匆匆的搭完,就算一万个侥幸能用又咋样呢,遇到问题还不是抓瞎。本来就是一套技术栈。拆解到单元再反向学习逆推。
知识点
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.