V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  GuuJiang  ›  全部回复第 12 页 / 共 20 页
回复总数  390
1 ... 4  5  6  7  8  9  10  11  12  13 ... 20  
2021-06-02 20:51:24 +08:00
回复了 zhoudaiyu 创建的主题 问与答 有几个关于 websocket 的疑问想问问大家
@zhoudaiyu 后者
2021-06-02 19:22:20 +08:00
回复了 zhoudaiyu 创建的主题 问与答 有几个关于 websocket 的疑问想问问大家
@zhoudaiyu 你这样一说就明白你的疑惑来自哪里了,实际情况是,发送“握手”使用的那个 http 总得要先有个 tcp 连接对吧,姑且称他为 A,“握手”的请求并不是为了开启一个新的连接 B,而是接着使用 A,只不过在 A 上承载的应用层协议摇身一变切换为了 ws 协议了
2021-06-02 15:41:42 +08:00
回复了 zhoudaiyu 创建的主题 问与答 有几个关于 websocket 的疑问想问问大家
1. 从历史进程来看,websocket 是晚于 http 诞生的,你想象下如果自己就是制定标准的那班哥们,现在面临一个新任务,需要设计一种浏览器能使用的,能够保持连接,且服务端能够主动发送数据的协议,那么你有两种选择,一种是基于 TCP 设计一个全新的协议,一种是看看能否在现有的 http 的基础上 hack 一下完成目标,于是一拍大腿,http 本来就基于 TCP,把这个现成的连接拿来用不就完事了,于是只需要设计出一种方法,通过一个 http 请求让双方都知道“现在我给你发了一个 http 请求,你处理完这个请求后咱们这次请求时使用的那个 TCP 连接先别关,且从现在开始,在这个连接上咱们开始玩一个新的协议,这个协议不如就叫它 ws 协议吧”,这就是第一个 http 请求里的“Connection: Upgrade”干的事,这样有个很大的好处,就是当服务端版本比较旧,还不支持 websocket 时,它收到的仍然是一个合法的 http 请求,只不过忽略了“Connection: Upgrade”而已,这样不会带来什么大的兼容性问题
2. 原因同上
3. 同上,这时候 nginx 相当于个中间人,于是它需要干两件事,一是自己处理“Connection: Upgrade”,将上游到 nginx 的连接切换为 websocket,二是把“Connection: Upgrade”忠实地传递下去,让下游能够处理,从而将 nginx 到下游的连接也切换为 websocket,当存在多级 nginx 时同理,每一级都要正确地完成这两件事,整个链条才能串起来
4. 是可以的,如果做 4 层转发那么上面完全透明,而如果是应用层,就像 nginx 这样,那就需要像上面提到的这样,不光耀转发 Upgrade,同时自己也需要能够响应 Upgrade
5. 在应用层最好不要随便使用“挥手”这个词,以免带来更多的误解,虽然我知道你真正想表达什么,答案也很简单,因为从处理完 Upgrade 那一刻开始,协议已经切换成 websocket 了
2021-05-30 13:18:14 +08:00
回复了 AndyAO 创建的主题 问与答 在 Git 中 pretty 是什么意思?
就是字面意思“好看”啊,对人类友好的展示方案
拿 json 举例,未 pretty 的 json 全部挤在一行,因为计算机解析时只需要标记就够了,而经过 pretty 以后就加入了额外的换行、tab 等排列成我们常见的那个树形格式,换行和 tab 对于解析来说是并不需要的,单纯就是为了让人类更容易看
2021-05-28 09:46:13 +08:00
回复了 coderstory 创建的主题 Java 深夜求助 Java 中 2 个线程怎么互相唤醒和挂起
@coderstory 我来帮你翻译下你的问题吧
你的意思无非就是 B 唤醒 A 以后自己并不是马上进入 wait,而是继续执行,由别的条件来让 B 进入 wait,这段时间 A 和 B 是同时执行的,由此可以推论所有只用一把锁(此处指广义的锁,无论是 synchronized 、j.u.c.Lock 、单 Lock 多 Condition 等)的方案通通都是不可行的,这些方案实现的两个线程互相唤醒的效果从时间线上看都是交替执行,这里顺便纠正一下你以及楼里部分人对 wait/notify 的一个常见误解,并不是说 B 调了 notify/notifyAll 以后 A 就开始执行了,B 调 notify 仅仅是让 A 开始进入锁的竞争,直到 B 进入 wait 、或者结束执行等其它方式离开临界区,A 成功竞争到锁后才真正开始执行的
回到你的问题来,再结合你下面说的应用场景,我觉得这大概率是个 XY 问题,先不说“前端调试后端”这个是否有误入歧途,光说前面这个问题,站在 B 的角度,从宏观上来说,你真的关心在 B 从调了 notify 到 wait 的这段时间 A 是不是真的开始执行了吗?这个对 B 来说理应是作为黑盒无感知的才对,如果你对这个有刚需,非要他们有一段并行的时间,那么一定是哪里出了问题,不要继续花心思在解决 Y 问题上了
2021-05-22 21:01:19 +08:00
回复了 Joeith 创建的主题 iPhone 企业微信有 Callkit 吗?怎样开启
@moooookey 用不用 callkit 唯一的区别就是接听界面是应用内的还是系统的,通话流量都是自己实现,不存在苹果代理这种说法
2021-05-21 15:51:33 +08:00
回复了 qwertyzzz 创建的主题 数据库 这个为什么会使用到索引呀
@qwertyzzz 这里指的是覆盖索引,简单说就是不需要回表,只要你查询的列全都属于索引自然就满足覆盖索引
@iminto 你才是属于以讹传讹吧,明明是你自己理解错误,谁说最左原则指的是在 where 里的顺序了?其实这是个简单的逻辑问题,如果 ABC 的组合是有序的,那么单独取出 AB 或者 A 仍然是有序的,这就是索引能继续发挥作用的原因,但是单独取出 B 、C 、BC 则不再是有序的,索引自然也就起不到作用了,这才是“最左原则”的本质
2021-05-19 16:31:21 +08:00
回复了 lrs 创建的主题 问与答 QUIC 协议基于 UDP, UDP 不可靠, QUIC 如何保证可靠性的呢
@PeakFish ???
2021-05-14 19:43:04 +08:00
回复了 liuchengfeng1 创建的主题 分享创造 请问抖音如何把多个视频分割成一个啊?如图
重新定义“分割”
2021-05-14 19:04:27 +08:00
回复了 3dwelcome 创建的主题 分享发现 看了 Windows 的 GUID 生成算法,惊掉我下巴。
@3dwelcome 只要一个东西是固定长度的,就不可能存在 100%不重复,鸽笼原理了解一下?
2021-05-12 18:17:38 +08:00
回复了 FaiChou 创建的主题 程序员 打印机的驱动是什么?
其实理论上所有的硬件都需要驱动,甚至包括 CPU,是的,你没看错,包括 CPU,倒回去十多年前,重装完系统后依次安装各种驱动简直就是家常便饭,甚至还因此而诞生了类似驱动之家这样的软件来简化这个过程,那为什么最近这几年主动去安装驱动这件事开始变得陌生了,一是因为操作系统本身已经内置了大量通用的驱动,并且硬件也趋于标准化,所以操作系统内置的驱动已经足以满足了,但是各种硬件定制化的新功能仍然还需要在安装特定的驱动后才能使用,最典型的例子就是刚装完系统时只能设置比较低的分辨率,等装完显卡驱动后才能设置更高的分辨率,二是因为系统本身以及各种 XXX 电脑管家具有联网自动查找并安装驱动的功能,在如今的网速下这个过程已经对用户无感了
2021-05-04 19:55:05 +08:00
回复了 zhongpingjing 创建的主题 Java 假如 CPU 只有一个核心,使用 CAS 并发竞争的问题
更正一下,甚至我自己说的“自旋锁只是其中一种手段”这句话都是不准确的,自旋并不是锁的必要条件,锁也不是靠自旋实现的,有没有自旋,自旋多少次都不影响锁行为的正确性,自旋的存在仅仅是作为“预期能够很快得到锁,自旋的代价小于 wait 的代价”这一前提下的一种优化手段而已,既然是优化,那自然是可以调整其参数甚至去掉的
如果“预期能很快得到锁”这个条件满足,那么自旋带来的收益就是正的,如果条件不满足,那还不如不自旋,而在单核条件下这个条件显然是不可能满足的,那关掉自旋(其实就是把自旋次数改为 0)也是一种很自然的选择
2021-05-04 19:29:29 +08:00
回复了 zhongpingjing 创建的主题 Java 假如 CPU 只有一个核心,使用 CAS 并发竞争的问题
@raysonx 这就是你和其他所有人分歧的出发点,没有人说过去掉锁啊,锁是目的,自旋锁只是其中一种手段,去掉自旋 != 去掉锁,不管怎么说,也改变不了在单核环境中自旋就是被优化掉了这个事实
2021-05-04 14:07:55 +08:00
回复了 zhongpingjing 创建的主题 Java 假如 CPU 只有一个核心,使用 CAS 并发竞争的问题
这篇帖子生动地展示了什么叫作“你在第二层,你以为我在第一层,实际我在第五层”
按照“是不是只能等 A 执行完毕”这样的表述,提问者应该在第一层,估计还没有形成时间片这个概念,于是第二层的人敏锐地意识到了这一点,指出了不管是不是单核,实际都有并发,但是这个帖子好巧不巧提到了自旋,于是引来了第五层的人,指出了在单核环境下自旋是无意义的,但是第二层的人无法区分第一层和第五层,把所有第五层的对手都当第一层的来辩论
其实跟各种软件自带一大堆重复的 dll 同样的理由,站在开发者的角度,肯定是统一的依赖管理更合理,然而站在小白用户的角度,更看重的是开箱即用,最终形成了这个恶性循环的局面
2021-04-30 20:32:11 +08:00
回复了 zhoudaiyu 创建的主题 Linux 今天遇到了一个 curl 的问题,感觉有点坑
@zhoudaiyu 你执行下 fg 命令还会有新的惊喜
2021-04-29 11:23:00 +08:00
回复了 James369 创建的主题 数学 概率中的 P(Ω)=1 应该怎么理解?
数学问题要从定义出发,不要从直觉出发,“独立”在概率论里只有一个明确的定义,那就是 P(A)P(B)=P(AB) ⇔ A 和 B 独立,因此把 P(Ω)=1 代进去,显然成立
2021-04-25 14:54:25 +08:00
回复了 Joker123456789 创建的主题 Java 问几个有关 NIO 的问题
我补充一下,确实存在同一个端口同时支持多种协议的情况,但这个和提问者想象的那个不是一回事,可以认为这个分发工作仍然是处在协议处理层,相当于一个复合的协议,具体实现时类似状态机,总之只需要记住一点,IO 部分是不关心上层协议的
2021-04-25 14:43:53 +08:00
回复了 Joker123456789 创建的主题 Java 问几个有关 NIO 的问题
恭喜你终于开始有点要逐步转到正确方向的迹象了,我来依次回答下你的每个问题,希望你哪天能正确认识到你在原来那个帖子里犯的错误是多么的基础和低级,并且向所有指出你问题的人一一道个歉
1. 不保证
2. 会
随时记住一点:TCP 是流式协议

关于分片的问题,任何分法都是有可能的,随时记住一点:TCP 是流式协议、TCP 是流式协议、TCP 是流式协议,对上层协议一无所知

关于协议解析的问题,在你选择了监听某个端口之前,这个端口期望收到的协议是已经提前确定了的,换句话说你需要自己负责按照预先的期望去解析协议,并不存在你想象中的“根据收到的内容自动判断协议”这种东西
@JasonLaw 以下描述不针对负载均衡类应用,而针对广义的抽象的 IO+业务处理
想象收银台(IO 模块)和厨房(业务模块)是两个独立的部门,对彼此是黑盒,收银台收到订单后将菜单交给厨房制作(读到数据后调用业务模块),厨房制作完成后将食品让收银台交给用户(业务处理完成后结果写回客户端),针对你的问题“当咖啡处理好了之后,是收银员将咖啡拿给顾客吗”,答案是是的,只有收银台才能和顾客打交道(持有连接)
那么每个部门内部可以分别独立地作出以下选择
收银台:
1. 一个顾客首次到来(建立连接)后指派一个专门的收银员(IO 线程)全程服务这个顾客直到他离开(断开连接),这就是阻塞式 IO,在这个过程中顾客完全可以点一样东西,思考几分钟,再点下一样,他思考的时候收银员就在等待(阻塞)
2. 一个收银员服务轮流服务所有顾客,并且只服务那些已经想好了(数据就绪)的顾客,如果顾客点了一样东西然后卡壳了,需要继续思考(就绪数据已读完),那么对不起,请你马上让开给下一个想好的顾客,等你想好了再来(下一轮 select/poll/epoll),当然收银员有职责记住每个顾客已点的部分食品,下一轮继续回来点的东西能够拼接上,最终形成完整订单(即上层协议的分割和解析,当然这一步严格来说到底算 IO 模块还是算业务模块暂时存疑,具体取决于期望 IO 模块的输出是 TCP 流还是上层协议内容),这就是非阻塞 IO
厨房:
1. 收银员递交订单后需要一直等着,直到拿到做完的东西后才能转身继续服务顾客,这就是同步调用
2. 收银员递交完订单后就转身继续服务顾客,厨房有需要的时候再把东西交给收银台,这就是异步调用

建立完这个模型后再来逐一进行整体的分析
1. 收银台采用阻塞式
优点
1) 和厨房打交道时既可以选择同步方式也可以选择异步方式,当然实际情况多采用同步,因为即使使用了异步,仍然会搭配 wait 等调用,本质上还是转化成同步了
2) 在描述收集整个订单(即上层协议解析)时可以站在收银员的角度,在写一些复杂协议时比较符合人的直觉,即当读完某一部分数据后可以根据需要主动地进行读操作,如果无数据可读就进入阻塞
缺点
1) 要么保证需要的收银员数量完全等于此刻所有处在点单过程中的顾客数量(即一客户端一线程),造成了大量的资源消耗(线程的内存等资源开销),甚至耗尽资源,要么给收银员人数设上限,从而导致了某些顾客无法分配到收银员(客户端连接被阻塞)
2) 即使收银员数量是充足的,但是收银员只有在收银台才能和顾客交互,所有的收银员只能轮流使用收银台(CPU 时间片),而收银台数量是有限的,且一个收银员用完收银台换下一个收银员用时必须要进行一些交接工作(线程上下文切换),那么当收银员数量多到一定程度时可能花在交接收银台上的时间比真正使用收银台的时间还要多
2. 收银台采用非阻塞式
优点
只需要一个或少数几个收银员就可以服务大量顾客
缺点
1) 通常来说和厨房打交道时就只能选异步方式了,当然这个没有任何强制,开发者也可以自行选择同步方式,但是如果业务是耗时操作,那带来的灾难就远大于阻塞式,因为这时不单阻塞了一个顾客,而是阻塞了所有顾客,这其实是一种典型的误用,我个人觉得真出现了这种情况,需要为之负责的是开发者自己,但是却有人觉得这是非阻塞式 IO 的缺陷,我是难以认同的
2) 协议解析、业务处理等部分不能再站在收银员的角度,即收银员无权主动要求读下一块数据,只能被动地接收数据,由顾客来驱动,这有点违反直觉,在写一些复杂协议的解析时需要人工改写为状态机,这也是有的人不习惯使用非阻塞 IO 的原因,无法扭转这个视角

回到你的问题来,我没深入研究过负载均衡类系统,所以不敢妄下结论,只能说说自己的猜测,即如果我自己来实现一个负载均衡系统的话会选择怎么做
还是老话,IO 和业务独立分析,IO 部分既然它们自己说了是非阻塞那就是非阻塞了,所以重点看业务部分,作为一个负载均衡系统,假设它的业务就是选择合适的后端->透传数据,从这个角度讲其实就是把两个反向的 IO 模块背靠背连接起来,并且以无状态的方式透传数据,那么可以认为它的业务是非常轻量的,不好用厨师的例子来做类比
1 ... 4  5  6  7  8  9  10  11  12  13 ... 20  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2840 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 30ms · UTC 13:44 · PVG 21:44 · LAX 05:44 · JFK 08:44
Developed with CodeLauncher
♥ Do have faith in what you're doing.