阅读视图

发现新文章,点击刷新页面。

CD往事

当年今日

周五晚上回家的路上,听的是陈奕迅的《幸福摩天轮》专辑。在这个专辑出之前,我也就已经知道了陈奕迅,但陈奕迅的这个专辑,是让我印象最深刻的。这个专辑大概是在我初中的时候推出的,当时班里的同学偶尔也会拿这个CD出来。但显然,初中同学买了CD一定不是正版的。到底正版的这些CD要去哪里买?那个时候实际上我也不知道,但是我高中的时候,同学拿出手的CD,就一定是正版的。有钱人和没钱人的区别真的很明显,高中同学可能为了买正版的CD去香港,但初中的同学,很多家里都不太富裕,即便算是有点零花钱,也不至于多到可以专门去香港买CD回来。他们也会买CD,但是相对于更不富裕的同学来说,那个CD的质量可能会好一点,但质量再好,也不是正版。

当我还买CD的时候,我也不知道自己到底买过多少正版。我甚至不知道如何区分正版和盗版。我有几个CD是在广州购书中心负1层音像制品那里买的,估计那几个应该是正版吧。还有一些CD是在石牌桥的某层楼买的,那里的CD,全部都是个打孔CD。显然那些CD在国内是不会有的,但是到底是用什么途径把那些从外国带进来我就不知道,反正那些CD都被打口了。

陈奕迅的《幸福摩天轮》和陈小春的《大明星》是我自己用零花钱买的第一批CD。那是我第一次买香港歌手的CD,是在赤岗路的某个音像店。陈奕迅的那个我是一定会买的,至于陈小春的到底要买哪一个,当时我还真犹豫了很很久。那是我买的第一和第二张CD,是同一天买的。好像是10块钱一张。那两张CD听的时候,我都是偷偷摸摸的,放在电脑的光驱里。买这两张CD的时候,家里没有VCD机,在早之前那个VCD机已经坏掉。但即便有VCD机,也没有单独的功放,所以要看要听VCD或者CD得开着电视。后来我终于找到了一个比较大的收录机,用莲花头的线连接VCD机和收录机后,我听CD才终于不需要开电视。但上面说到的那两个CD,我从来没有用家里的VCD机播放过。那两张是我听得最多的CD,虽然电脑的光驱完全没有纠错功能,所以一旦CD有任何瑕疵,一定会出问题,但是起码在我疯狂地不断重复播放那两张CD的时候,那两张光盘都没有出过任何问题。我从来都不选歌,都是从第一首听到最后一首,不断循环播放。听到一定程度我知道这一首歌的下一首是什么,我知道其实听歌的时候完全不需要有这种预判,但是这种预判是控制不住的,是自己涌出来的。因为一开始我就是用电脑的光驱播放那两个CD,于是我同时发现陈小春的那个CD里面居然有一些壁纸。这是我万万想不到的,但陈奕迅的那张没有。后来我又在同一家音像店买了不少CD,但再也没有发现过CD里面有壁纸。

在戴上耳塞听陈奕迅的《幸福摩天轮》专辑之前,我的脑子里全部都是VBA, 但音乐开始播放以后,我总算整个人都松弛了下来。

音乐的确可以拯救我们,只是我感觉我已经好久都没有主动地让音乐放松我自己了。

一堆可拍照的古董设备的成像效果「多图」

很早之前就想做了,然后一直拖……一直拖……想起有这么个事,但天气不好……一直拖……一直拖……一直一直拖……

终于在了一个晴天多云的日子,找了个看起来还不错挺干净的景,背着一大包的设备,在同一时间段同一角度拍照片。


设备列表

根据设备购买年份排序

  • Canon PowerShot A3300 IS
  • Nokia C2-00
  • Nintendo 3DS
  • Sony Ericsson Xperia mini pro, SK17i
  • 红米2
  • VIVO Y51A
  • Sony Xperia XZ1
  • iPhone 8

都是古董。

本来手里能拍照的设备还有一个小米平板1和iPad4,但是反复检查了好几遍这俩机器,还检查了定期备份,都没发现当日的照片。可能是忘记拍摄了?

红米1虽然也能拍照,但是早就自杀无法开机了。

拍照效果

因为是无限远景,所以均未使用手动对焦。而且非触屏设备也没有手动对焦的功能。

所有图片均为原图,保留了EXIF信息但删除了所有GPS相关的meta。文件使用 Leanify 的 mozjpeg 进行无损压缩。

想要查看具体的EXIF信息,可以另存图片到本地,然后用EXIF工具查看。

图片是走 Cloudflare CDN 的,因为都是原图所以文件比较大,国内打开很慢很正常。

Canon PowerShot A3300 IS

1600万像素(4608 × 3456)。CCD。未使用光学变焦。

image_IMG_6646_a3300

image_IMG_6647_a3300

image_IMG_6648_a3300

image_IMG_6649_a3300

Nokia C2-00

30万像素(640 × 480)。

2007怀旧画质。

image_0002_c2-00

image_0003_c2-00

Nintendo 3DS

30万像素(640 × 480)。未使用3D效果。

2007怀旧画质 x2。老任个抠逼用这么低端的硬件也是传统艺能了。

image_HNI_0026_3ds

image_HNI_0027_3ds

Sony Ericsson Xperia mini pro, SK17i

500万像素(2592 × 1944)。使用 Free Xperia Project, CyanogenMod-7.2.0-mango 系统的相机应用。

不对比都发现不了,这手机拍照发黄?赶紧翻了下2013年时拍的照片,发现还真的偏黄,只是不严重,单拿出来发现不了。

image_IMG_19800107_225749_sk17i

image_IMG_19800107_225753_sk17i

红米2

800万像素(3264 × 2448)。使用 LineageOS 15.1-20200223-NIGHTLY-wt88047 系统的相机应用。

拍第一张的时候自动光圈抽风,非常暗。

拍第二张的时候,这镜头前飞过来的这是个啥虫子???

反正这画质是够烂了,当年那么多人吹小米拍照(现在也很多人吹),也不知道有多少是水军。

image_IMG_20230825_154135_hongmi2

image_IMG_20230825_154143_hongmi2

VIVO Y51A

800万像素(3264 × 2448)。使用系统自带拍照应用。

如果说 SK17i 是发黄,那 Y51A 就是发蓝。

image_IMG_20230825_154134_y51a

Sony Xperia XZ1

1700万像素(5504 × 3096)。使用系统自带拍照应用。自动模式,未开启 HDR。

像素比相机A3300还高,清晰度明显更占优势。但在手机镜头的硬件功能上差很多,相机永远是相机。

image_DSC_7854_xz1

image_DSC_7855_xz1

iPhone 8

1200万像素(4032 × 3024)。使用系统自带拍照应用。自动模式,开启 HDR。使用JPG作为保存格式。(垃圾HEIF)

破玩意卖得贼拉贵,像素低,颜色微微发蓝(当然可能是太阳光照角度的问题。天气嘛,变幻莫测)。

image_IMG_0085_iphone8

image_IMG_0086_iphone8

image_IMG_0087_iphone8


对比

以佳能A3300为基准做对比。

使用 BCompare 进行对比。对像素较少的图片进行缩放,以高度未基准(这意味着XZ1这个有更高分辨率但图像高度低,要被放大后才能追上A3310)。

几个不是一个级别的硬件就不跟 A3300 比了,其实也就 3DS 和 C2-00 单拿出来比一下就好。

3DS VS C2-00

screenshot_on_b85m_by_flameshot_at_2024-03-25_00-31-40

XZ1 VS A3300

screenshot_on_b85m_by_flameshot_at_2024-03-25_00-44-46

红米2 VS A3300

screenshot_on_b85m_by_flameshot_at_2024-03-25_00-38-38

Y51A VS A3300

screenshot_on_b85m_by_flameshot_at_2024-03-25_00-40-29

SK17i VS A3300

screenshot_on_b85m_by_flameshot_at_2024-03-25_00-41-35

iPhone8 VS A3300

screenshot_on_b85m_by_flameshot_at_2024-03-25_01-09-43


总结

都是古董。

以 A3300 的战斗力仍然能坚挺。2011年的千元卡片机直到2017年才被高端手机追平(还得是无光学变焦的前提下)。

只不过现在有 HDR 这种东西存在,解决了高对比度高点光源的问题,拍照难度下降一大截,而且现在手机都是多镜头(个人认为屁用没有,我甚至怀疑各个APP是否有真的调用过多镜头)。

而且索尼的运营策略也太过奇葩,就如同applemiku说的:索尼的产品总是把本应能做的功能,硬是留到下一代产品当卖点,恶心人,明显拥有两个版本周期的巨大优势,硬是要拖到下一个版本,然后发布出来时仍是半成品,然后半个版本周期内友商就做出来完成品,两个版本周期的巨大优势 被硬搞成 半个周期的一般特性,手机照相APP的HDR功能就是,默认不开启,必须进入手动模式才开启,然后内核不支持RAW进而导致第三方应用无法支持硬件HDR,作为一个卖点是照相的拍照手机来讲,这一块做得实在太拉胯了。更别说索尼还搞了个基于相机+六轴感应实现的3D建模扫描,做到一半服务器也崩了,谷歌Drive接口也崩了,崩得一塌糊涂,结果三星下一个版本就做出来了更好的应用,并作为核心卖点进行宣传,行业内甚至都没人想得起这玩意其实是索尼先开始做的。

反正现在我拍照也不拍场照了,漫展什么的自从荷花遍地之后就不感兴趣了,跑展甚至看不到什么原创商品,以前认识的作者基本上全都退圈了(不然呢,快40多岁还跑展摆摊,那身体得多棒才跑得动)。

现在拍照基本上就是拍拍景。点光源特别亮的那种景,即使是现在有 HDR 的手机也没见谁拍出来(猜测是人的拍照技术问题)。拍人的话顶多就是给家里老人拍照片,人家要求必须要用短视频APP开美颜拍照然后自动配乐……就当哄老人乐子了,什么构图什么清晰度都不需要。

再说现在遍地魔怔人。前几天我说我有台 Xperia ,结果某个群里就嘲讽上「这么破旧的手机你也用」,我也没说我用的是啥型号,Xperia 1 V 是2023年5月发布的,还不满一年。这就有人跳起来嘲讽,这互联网上疯子是真多了。

当然我是想买新手机新相机的,但是没钱。

The post 一堆可拍照的古董设备的成像效果「多图」 first appeared on 石樱灯笼博客.

ETCD的内存问题

今天跟大家分享一个etcd的内存大量占用的问题,这是前段时间在我们开源软件Easegress中遇到的问题,问题是比较简单的,但是我还想把前因后果说一下,包括,为什么要用etcd,使用etcd的用户场景,包括etcd的一些导致内存占用比较大的设计,以及最后一些建议。希望这篇文章不仅仅只是让你看到了一个简单的内存问题,还能让你有更多的收获。当然,也欢迎您关注我们的开源软件,给我们一些鼓励。

为什么要用ETCD

先说一下为什么要用etcd。先从一个我们自己做的一个API网关 – Easegress(源码)说起。

Easegress 是我们开发并开源的一个API应用网关产品,这个API应用网关不仅仅只是像nginx那样用来做一个反向代理,这个网关可以做的事很多,比如:API编排、服务发现、弹力设计(熔断、限流、重试等)、认证鉴权(JWT,OAuth2,HMAC等)、同样支持各种Cloud Native的架构如:微服务架构,Service Mesh,Serverless/FaaS的集成,并可以用于扛高并发、灰度发布、全链路压力测试、物联网……等更为高级的企业级的解决方案。所以,为了达到这些目标,在2017年的时候,我们觉得在现有的网关如Nginx上是无法演进出来这样的软件的,必需重新写一个(后来其他人也应该跟我们的想法一样,所以,Lyft写了一个Envoy。只不过,Envoy是用C++写的,而我用了技术门槛更低的Go语言)

另外,Easegress最核心的设计主要有三个:

  • 一是无第三方依赖的自己选主组集群的能力
  • 二是像Linux管道命令行那样pipeline式的插件流式处理(支持Go/WebAssembly)
  • 三是内置一个Data Store用于集群控制和数据共享。

对于任何一个分布式系统,都需要有一个强一制性的基于Paxos/Raft的可以自动选主机制,并且需要在整个集群间同步一些关键的控制/配置和相关的共享数据,以保证整个集群的行为是统一一致的。如果没有这么一个东西的话,就没有办法玩分布式系统的。这就是为什么会有像Zookeeper/etcd这样的组件出现并流行的原因。注意,Zookeeper他们主要不是给你存数据的,而是给你组集群的。

Zookeeper是一个很流行的开源软件,也被用于各大公司的生产线,包括一些开源软件,比如:Kafka。但是,这会让其它软件有一个依赖,并且在运维上带来很大的复杂度。所以,Kafka在最新的版本也通过内置了选主的算法,而抛弃了外挂zookeeper的设计。Etcd是Go语言社区这边的主力,也是kubernetes组建集群的关键组件。Easegress在一开始(5年前)使用了gossip协议同步状态(当时想的过于超前,想做广域网的集群),但是后发现这个协议太过于复杂,而且很难调试,而广域网的API Gateway也没遇到相应的场景。所以,在3年前的时候,为了稳定性的考量,我们把其换成了内嵌版本的etcd,这个设计一直沿用到今天。

Easegress会把所有的配置信息都放到etcd里,还包括一些统计监控数据,以及一些用户的自定义数据(这样用户自己的plugin不但可以在一条pipeline内,还可以在整个集群内共享数据),这对于用户进行扩展来说是非常方便的。软件代码的扩展性一直是我们追求的首要目标,尤其是开源软件更要想方设法降低技术门槛让技术易扩展,这就是为什么Google的很多开源软件都会选使用Go语言的原因,也是为什么Go正在取代C/C++的做PaaS基础组件的原因。

背景问题

好了,在介绍完为什么要用etcd以后,我开始分享一个实际的问题了。我们有个用户在使用 Easegress 的时候,在Easegress内配置了上千条pipeline,导致 Easegress的内存飙升的非常厉害- 10+GB 以上,而且长时间还下不来。

用户报告的问题是——

在Easegress 1.4.1 上创建一个HTTP对象,1000个Pipeline,在Easegres初始化启动完成时的内存占用大概为400M,运行80分钟后2GB,运行200分钟后达到了4GB,这期间什么也没有干,对Easegress没有进行过一次请求。

一般来说,就算是API再多也不应该配置这么多的处理管道pipeline的,通常我们会使用HTTP API的前缀把一组属于一个类别的API配置在一个管道内是比较合理的,就像nginx下的location的配置,一般来说不会太多的。但是,在用户的这个场景下配置了上千个pipeline,我们也是头一次见,应该是用户想做更细粒度的控制。

经过调查后,我们发现内存使用基本全部来自etcd,我们实在没有想到,因为我们往etcd里放的数据也没有多少个key,感觉不会超过10M,但不知道为什么会占用了10GB的内存。这种时候,一般会怀疑etcd有内存泄漏,上etcd上的github上搜了一下,发现etcd在3.2和3.3的版本上都有内存泄露的问题,但都修改了,而 Easegress 使用的是3.5的最新版本,另外,一般来说内存泄漏的问题不会是这么大的,我们开始怀疑是我们哪里误用了etcd。要知道是否误用了etcd,那么只有一条路了,沉下心来,把etcd的设计好好地看一遍。

大概花了两天左右的时间看了一下etcd的设计,我发现了etcd有下面这些消耗内存的设计,老实说,还是非常昂贵的,这里分享出来,避免后面的同学再次掉坑。

首当其冲是——RaftLog。etcd用Raft Log,主要是用于帮助follower同步数据,这个log的底层实现不是文件,而是内存。所以,而且还至少要保留 5000 条最新的请求。如果key的size很大,这 5000条就会产生大量的内存开销。比如,不断更新一个 1M的key,哪怕是同一个key,这 5000 条Log就是 5000MB = 5GB 的内存开销。这个问题在etcd的issue列表中也有人提到过  issue #12548 ,不过,这个问题不了了之了。这个5000还是一个hardcode,无法改。(参看 DefaultSnapshotCatchUpEntries 相关源码

// DefaultSnapshotCatchUpEntries is the number of entries for a slow follower
// to catch-up after compacting the raft storage entries.
// We expect the follower has a millisecond level latency with the leader.
// The max throughput is around 10K. Keep a 5K entries is enough for helping
// follower to catch up.
DefaultSnapshotCatchUpEntries uint64 = 5000

另外,我们还发现,这个设计在历史上etcd的官方团队把这个默认值从10000降到了5000,我们估计etcd官方团队也意识到10000有点太耗内存了,所以,降了一半,但是又怕follwer同步不上,所以,保留了 5000条……(在这里,我个人感觉还有更好的方法,至少不用全放在内存里吧……)

另外还有下面几项也会导致etcd的内存会增加

  1. 索引。etcd的每一对 key-value 都会在内存中有一个 B-tree 索引。这个索引的开销跟key的长度有关,etcd还会保存版本。所以B-tree的内存跟key的长度以及历史版本号数量也有关系。
  2. mmap。还有,etcd 使用 mmap 这样上古的unix技术做文件映射,会把他的blotdb的内存map到虚拟内存中,所以,db-size越大,内存越大。
  3. Watcher。watch也会占用很大的内存,如果watch很多,连接数多,都会堆积内存。

(很明显,etcd这么做就是为了一个高性能的考虑)

Easegress中的问题更多的应该是Raft Log 的问题。后面三种问题我们觉得不会是用户这个问题的原因,对于索引和mmap,使用 etcd 的 compact 和 defreg (压缩和碎片整理应该可以降低内存,但用户那边不应该是这个问题的核心原因)。

针对用户的问题,大约有1000多条pipeline,因为Easegress会对每一条pipeline进行数据统计(如:M1, M5, M15, P99, P90, P50等这样的统计数据),统计信息可能会有1KB-2KB左右,但Easegress会把这1000条pipeline的统计数据合并起来写到一个key中,这1000多条的统计数据合并后会导致出现一个平均尺寸为2MB的key,而5000个in-memory的RaftLog导致etcd要消耗了10GB的内存。之前没有这么多的pipeline的场景,所以,这个内存问题没有暴露出来。

于是,我们最终的解决方案也很简单,我们修改我们的策略,不再写这么大的Value的数据了,虽然以前只写在一个key上,但是Key的值太大,现在把这个大Key值拆分成多个小的key来写,这样,实际保存的数据没有发生变化,但是RaftLog的每条数据量就小了,所以,以前是5000条 2M(10GB),现在是5000条 1K(500MB),就这样解决了这个问题。相关的PR在这里 PR#542

总结

要用好 etcd,有如下的实践

  • 避免大尺寸的key和value,一方面会通过一个内存级的 Raft Log 占大量内存,另一方面,B-tree的多版本索引也会因为这样耗内存。
  • 避免DB的尺寸太大,并通过 compact和defreg来压缩和碎片整理降低内存。
  • 避免大量的Watch Client 和 Watch数。这个开销也是比较大的。
  • 最后还有一个,就是尽可能使用新的版本,无论是go语言还是etcd,这样会少很多内存问题。比如:golang的这个跟LInux内核心相关的内存问题 —— golang 1.12的版sget的是 MADV_FREE 的内存回收机制,而在1.16的时候,改成了 MADV_DONTNEED ,这两者的差别是,FREE表示,虽然进程标记内存不要了,但是操作系统会保留之,直到需要更多的内存,而 DONTNEED 则是立马回收,你可以看到,在常驻内存RSS 上,前者虽然在golang的进程上回收了内存,但是RSS值不变,而后者会看到RSS直立马变化。Linux下对 MADV_FREE 的实现在某些情况下有一定的问题,所以,在go 1.16的时候,默认值改成了 MADV_DONTNEED 。而 etcd 3.4 是用 来1.12 编译的。

最后,欢迎大家关注我们的开源软件! https://github.com/megaease/ 

(全文完)

(转载本站文章请注明作者和出处 酷 壳 – CoolShell ,请勿用于任何商业用途)

The post ETCD的内存问题 first appeared on 酷 壳 - CoolShell.
❌