Unix `/proc/$/status` 的数据格式是如何设计的?
如果运行 cat /proc/$$/status | grep Sig
,你会看到当前进程的关于如何处理信号的配置。
- SigQ: 进程 real user id 的信号队列中的信号数量
- SigPnd: Pending 的信号数量
- SigBlk: 堵塞的信号
- SigLg: 忽略的信号
- SigCgt: 捕获的信号
如果见到 SigCgt: 000000004b817efb
,并不是说捕获了 4b817efb 个信号,而是说当前进程想要捕获哪些信号。这个数字可以转化为 01001011 10000001 01111110 11111011
,其中每个比特位代表一种信号类型,例如最后的 1 是 SIGHUP, 倒数第二个 1 是 SIGINT。
如果想要忽略 ctrl-c, 就可以用 signal(SIGINT, SIG_IGN …
Real User ID v/s Effect User ID v/s ...
Unix 操作系统鉴别用户的方式是通过内核提供的 user identifier (user ID, uid) 这个值。UID 会和一个 group identifier (GID) 相关联,用于决定系统资源的访问权限。命令行工具 id
可以查看当前用户的 UID 以及用户名,组。关于跑着的进程,会涉及到好几个 UID 的概念:
- euid, Effective user ID:系统用于检查权限。进程新建文件时,文件的 owner 也会用进程的 euid。
- fsuid, File system user ID: 历史上曾经出现过的一个概念,简单可以理解为就是 euid。
- suid, Saved user ID: 进程跑着的时候,需要降权做一些操作 …
穿越虫洞 - 学习 Facebook Pub/Sub 系统设计
Wormhole 是 Facebook 发布的 pub/sub 系统,它的设计目标是实时地,可靠地,将一个数据库的数据发送到多个订阅者服务那里去。订阅者服务可以是缓存(要更新数据),服务(要重建索引或更新数据),数据仓库(灌数据进 Hadoop, Hive)。
这个系统有三个核心组件:
- Producer: 一个 library,内建在应用方的程序里面。
- Publisher: 持续读 bin log 数据,转为实时流发送到别的系统去。
- Consumer
这个系统有一些有用的特性,例如:
- Shard 的数据库可以并行地运行虫洞 publisher
- 支持从检查点重新开始产生流,做故障恢复
- 可靠的有序的递送,消息至少会被发送一次,最近更新的数据会被更晚送达。
- 只要是 bin log 中出现的数据,publisher 就会递送它。
- 基于 stream,延迟很低 …
如何防止软件失效将变为灾难!
千年虫问题是进入 21 世纪时软件行业的大问题,大家都如临大敌,为此整整准备了一年甚至更久,写了各种脚本,更新了所有软件。有的 SA 甚至可以放心的离开岗位去休假。千年虫问题可能没那么严重,但行业对其的反应折射出了我们对风险对抗的认知:及时修复,降低风险,使软件失效不至于编程大灾难。
我们对于灾难的预处理,基本上都围绕着降低风险来做。如果有地方会引起问题,我们就会加倍注意。越大的可能性会引起我们越多的注意力。我们可能无法想到所有的可能性,但至少能处理已知的问题。
设立独立的安全区是一个常见的手段,在这个安全区里面我们想办法让这个子系统能够容忍风险,然后在想办法尽可能地将它与外部系统做好隔离。事实上,PR 和 code review 就是一种降低风险的手段,让别人和你一起把风。
另外一种手段是让系统尽可能的可预知,我们预测系统所有可能的状态,遍历所有的状态,要么想出怎么人工处理,要么修复它。
小步快跑也是个降低风险的手段,每次做一点改变。
read more如何设计像 Kafka 这样的分布式日志系统的存储方案?
日志是一种线性序的,只增加数据的数据结构,通常来说内容就是时间戳和内容数据,被添加到文件的末尾。虽然说起来这么简单,但要做到满足企业海量的日志数据的生成,就得引入像 Kafka 这样的系统。企业需求:高性能,高可用,可扩展,为了满足这些,我们也就要去实现领导选举,数据 replication,日志持久化,消息队列等等。
跟消息队列不同的是,消息只会被添加不会被删除,另外有基于某些规则的保留 (retention)能力。我们还有一些需求是定点重放,从某个日志记录开始读取数据,这意味着我们要做二分查找。
理论上来说,日志是无限增长的,单纯的文件不足以应对无限的数据。为了解决数据存储, Kafka 引入了 Chunk,不直接存储数据进文件,而是存进一个个小区块里,再把区块的索引登记到 index file 里。
为了性能考虑,我们尽可能要用到操作系统的页缓存,避免磁盘读操作。为此我们数据存储的时候可以直接将数据格式设定存储网络序,这样从内存页中可以直接转到 socket buffer 上(zero …
read more把用户丢来的 BUG 标记为不解决(Won't Fix)
做工程的首要考虑,既不是安全,也不是性能,而是能工作,能用。我们设计系统愿望总是好的,希望它每一个状态我们都能考虑到,但事实是,总有可能有意料之外的输入或影响,因此设计一个能容错的,能接纳不一致状态的系统是有意义的。本文提到了作者在处理请求 hostname 和 证书签的不一样,但作者决定还是承认这是可以用的输入,因为在一些特定的场景,仍然想让其工作,所以作者将那个 Case 标为 不解决。
衍生思考:作者做了一个 Tradeoff,在安全和快猛糙中间选择了快猛糙。事实上,作者遇到的场景并不只有这个解法,但他想说的问题相信很多人都在经历:任务无穷无尽,我们要做出一个对于当下合理的选择,这可能会有一些代价,但也是值得的。
read moreWeb 应用程序的缓存方案如何选择?
当 Web 应用程序遇到流量增长,上缓存就是必须的手段,因为缓存让我们不再读取磁盘,减少 IO,是个能快速提升系统性能的手段。论方法,Web 程序使用的缓存有两种:进程内和进程外。
- 进程内的缓存:使用诸如 Python
@lru_cache
之类的方法在进程里面缓存住返回值。好处是没有方法能比它更快了更简单了,你甚至不需要做序列化,任何编程语言的对象或者结构数据都能放进缓存。缺点是没法在进程间共用,程序重启需要重新构建缓存。 - 进程间的缓存:使用诸如 Memcached,Redis 等工具。利弊和上面相反,速度降了,需要做数据序列化,但能多进程多主机共用,程序重启不影响缓存。
引入缓存后,一个特别需要注意的问题就是何时让缓存过期,毕竟方法过段时间可能会返回不同的值。最简单的方法是设置过期时间,例如 1h, 1d 等。另外的做法是做更新或删除操作的时候主动清缓存,不过实现就麻烦了,尽管大多人会选择这个方案。
read more