[{"title":"成都三天两夜深度游攻略(8.27-8.30)","url":"https://qixin.ch/posts/chengdu/","body":"📅 行程概览\n\n8月27日(周一):下午抵达 → 宽窄巷子 → 晚餐火锅 → 锦里夜景\n8月28日(周二):都江堰+青城山一日游 → 返程后夜游九眼桥\n8月29日(周三):熊猫基地 → 春熙路+太古里 → 人民公园体验 → 奎星楼街小吃\n8月30日(周四):文殊院 → 午餐后返程\n\n📍 每日行程详解\n🔹 Day 1:老城烟火气初体验\n14:00-15:30 抵达与入住\n\n双流机场乘地铁10号线转2号线至春熙路/宽窄巷子附近酒店(约50分钟),推荐住宽窄巷子周边,方便出行。\n\n15:30-18:00 宽窄巷子漫步\n\n打卡宽巷子的老茶馆(如“三只耳”)、窄巷子的创意小店,体验掏耳朵(约20元)。\n必吃美食:\n\n小龙翻大江火锅(宽窄巷子店):古风装修,推荐毛肚、冰球鹅肠。\n甘食记肥肠粉:非遗美食,红油汤底配锅盔超香。\n\n\n\n18:30-20:00 晚餐推荐\n\n大龙燚火锅(太古里店):本地人常去,麻辣牛肉和霸王牛肉必点。\n\n20:30-22:00 锦里夜景\n\n灯光下的三国主题古街,推荐:\n\n小吃:三大炮(现做糯米球淋红糖)、糖油果子(外酥里糯)。\n体验:川剧变脸表演(门票约80元/人)。\n\n\n\n🔹 Day 2:世界遗产与自然奇观\n07:00-08:30 都江堰景区\n\n地铁2号线至犀浦站,换乘高铁至都江堰(10元/人,20分钟),建议买7:17的S5063次。\n游览路线:离堆公园 → 宝瓶口 → 飞沙堰 → 鱼嘴 → 伏龙观,全程约3小时。\n必看:千年水利工程的精妙设计,推荐跟导游讲解(约50元/人)。\n\n12:00-13:30 午餐推荐\n\n尤兔头(幸福店):麻辣兔头和鲜锅兔是招牌,本地人从小吃到大。\n\n14:00-17:00 青城山(前山)\n\n都江堰景区门口乘公交101路至青城山(10分钟),门票80元,索道单程35元。\n游览路线:月城湖 → 上清宫 → 老君阁,登顶俯瞰层峦叠嶂,感受道教文化。\n\n18:30-20:00 返程与晚餐\n\n高铁返回成都,晚餐可尝试饕林餐厅(春熙路店):非遗川菜,推荐饕林河渡鱼和辣子鸡。\n\n20:30-22:30 九眼桥夜生活\n\n酒吧街推荐:\n\nspace club:电音派对,适合年轻人狂欢。\n贰麻酒馆:中式调酒,熊猫酒仙和晕茶必点。\n\n\n\n🔹 Day 3:国宝萌趣与市井慢生活\n07:30-10:30 成都大熊猫基地\n\n地铁3号线至熊猫大道站,打车10分钟到基地,建议买7:30的上午票(55元/人)。\n游览路线:月亮产房(看幼崽)→ 太阳产房 → 1号别墅(成年熊猫),建议租电瓶车(10元/人)。\n贴士:带小风扇和防晒帽,8月底气温较高。\n\n11:30-13:00 春熙路+太古里\n\n打卡IFS顶楼的爬墙熊猫,逛方所书店、MUJI旗舰店。\n必吃美食:\n\n马旺子·川小馆(太古里店):百年老店,宫保茄香虾球和麻婆豆腐超赞。\n西月城谭豆花:馓子豆花和冰醉豆花解腻。\n\n\n\n14:00-16:00 人民公园体验\n\n鹤鸣茶社:百年茶馆,点一杯竹叶青(20元),划船(30元/30分钟)。\n推荐活动:相亲角(东门附近)、坝坝舞(下午常有)。\n\n16:30-18:00 奎星楼街小吃\n\n步行10分钟可达,必吃:\n\n冒椒火辣串串(下午5点营业):冷锅串串,兔腰和牛肉小郡肝必拿。\n熊姐大碗面:豪华面六种浇头,汤底浓郁。\n\n\n\n🔹 Day 3:文化沉淀与返程\n09:00-11:00 文殊院\n\n免费开放的千年古刹,推荐:\n\n素斋:香园餐厅(人均50元,素椒杂酱面和素包子)。\n文创:文殊院书店的佛系周边(如“平安”手绳)。\n\n\n\n11:30-13:00 午餐推荐\n\n洞子口张老二凉粉(文殊院店):甜水面和黄凉粉是招牌,本地人从小吃到大。\n\n13:30 返程\n\n地铁1号线至双流机场(约40分钟),建议预留1小时安检。\n\n📌 实用贴士\n\n\n交通:\n\n地铁:下载“天府通”APP扫码乘车,2号线覆盖主要景点。\n打车:市区内景点间约15-30元,夜间加20%服务费。\n\n\n\n门票预约:\n\n熊猫基地:提前7天在官方公众号“成都大熊猫繁育研究基地”抢票,上午票更抢手。\n都江堰/青城山:非高峰时段无需预约,直接在“青城山都江堰”公众号购票。\n\n\n\n天气与装备:\n\n8月底多雨,需带折叠伞和防滑鞋;白天炎热,建议穿速干衣+防晒帽。\n\n\n\n防坑指南:\n\n锦里/宽窄巷子的银器店谨慎购买,可能溢价严重。\n警惕景区周边“低价一日游”,建议通过正规平台预订。\n\n\n\n🍜 美食地图\n区域推荐餐厅必点菜品人均消费\n宽窄巷子小龙翻大江火锅毛肚、冰球鹅肠120元\n奎星楼街冒椒火辣串串兔腰、牛肉小郡肝60元\n春熙路马旺子·川小馆宫保茄香虾球80元\n文殊院洞子口张老二凉粉甜水面、黄凉粉15元\n九眼桥贰麻酒馆熊猫酒仙、晕茶80元\n\n📸 拍照打卡点\n\n宽窄巷子:井巷子的“砖文化墙”、星巴克臻选店的熊猫元素。\n都江堰:鱼嘴处拍岷江分流全景。\n青城山:老君阁旁的“青城天下幽”石碑。\nIFS熊猫雕塑:顶楼天台与熊猫合影(建议早上去人少)。\n\n希望这份攻略能让你尽情感受成都的“巴适”与“安逸”,祝你旅途愉快!🌿\n","description":""},{"title":"你无法通过优化成为一个好人","url":"https://qixin.ch/posts/good-man/","body":"我每次都试图做出完美的道德选择。这侵蚀了我的人性。\n我是一个正在恢复中的优化者。\n过去几年里,我花了大量时间纠结于每一个决定,因为我觉得自己必须做到最好。不是还行的事,不是好事——而是道德上最好的事。\n我停止了一部儿童小说的创作,因为开始怀疑它对任何人都不会有帮助。我责备自己没有每天冥想,尽管我知道这能让我成为一个更善良的人。我花了一年时间为一段分手哭泣,因为我害怕自己刚刚失去了最佳的灵魂伴侣,现在注定要过上一种次优的生活,一种无法达到其应有意义、未能充分发挥潜力的生活。\n我以为可能只是我这样,一个焦虑的千禧一代,带着完美主义倾向。但后来我注意到其他人也有同样的思维方式。\n有位朋友总是在晚餐时烦恼,担心自己选择的职业能否对世界产生足够大的积极影响。另一位朋友将一天划分为 15 分钟的增量,并记录下每一刻所做的事情,以免浪费任何时间。还有一位朋友——我最好的朋友——哭着打电话给我,因为尽管她花了数月时间悉心照料伴侣垂危的母亲,却仍担心自己未能让她的最后时光尽可能快乐。\n“我的情绪妨碍了我,”她自责道。“我真希望自己能像个机器人一样。”\n我特别注意到,认同有效利他主义(EA)的同龄人中存在这种思维方式。有效利他主义是一场社会运动,其核心在于利用数据和理性来找出如何“更好地行善”或“尽你所能做最大的善事”,引用两位 EA 主要思想家的书名。该运动敦促人们向每美元能拯救最多生命的慈善机构捐款。我听到其追随者哀叹,当他们走过无家可归者时感到多么糟糕,内心涌起帮助的冲动,却强迫自己不去行动,因为他们的一美元能为低收入国家的贫困人口带来更大的益处。\n这一切感觉不仅仅是许多人之前听说过的“优化文化”。它不是那种追求身体完美,推动你接受 Soylent 和补充剂、间歇性禁食和冰浴、Fitbits、Apple Watches 和 Oura Rings 的文化。它也不是那种专注于微调心灵,推动你尝试智能药物、多巴胺禁食和幸福追踪的文化。\n这是优化文化的另一条线索,虽较少被分析却更为雄心勃勃,因为它不仅针对身体或心灵,而是直指圣杯:你的灵魂。这是关于道德优化的探讨。\n这种思维方式在象牙塔中和街头巷尾一样普遍。带有功利主义倾向的哲学家告诉我们,仅仅做好事是不够的——我们必须尽可能做到最好。我们必须从数学上量化道德善行,以便能够最大化它。如今,这种驱动力在越来越多的圈子里显现出来,从利用技术“优化”冥想以期成为更好人的精神追求者,到试图将伦理编程入机器的人工智能研究者。\n我想了解这个想法的来源,以便弄清楚为什么我们中的许多人似乎越来越执着于它——这样我就能诚实地评估它的优点。我们的道德生活可以被优化吗?如果可以,应该这样做吗?还是我们已经将优化推向了其最佳极限之外?\n我们如何开始相信道德优化\n“我们正处于一条长达 400 年的趋势线的顶端,”犹他大学的哲学家 C. Thi Nguyen 告诉我。他解释说,优化的故事实际上是数据的故事:它是如何被发明的,以及在过去几个世纪中是如何发展的。\n正如历史学家玛丽·普维在她的著作《现代事实的历史》中所论述的那样,这一故事可追溯至 16 世纪,当时欧洲人提出了一个极具吸引力且革命性的知识项目——复式记账法。这一新型会计体系强调以精确、客观、可量化的方式记录每位商人的活动,使得任何人在任何地点都能进行核实。换言之,它开创了数据的概念。\n从一开始,人们就将优化视为一种神圣的力量。\n这为 17 世纪和 18 世纪的巨大智力发展铺平了道路——对于聪明的欧洲人来说,那是一个非常激动人心的时代。那是理性时代!启蒙时代!像弗朗西斯·培根和约翰内斯·开普勒这样的人看到了簿记的创新,并认为:这种将世界分割成可量化和可验证的数据块的方式非常棒。我们应该在我们正在构建的这个名为科学方法的新事物中模仿它。\n与此同时,17 世纪的哲学家布莱兹·帕斯卡尔提出了一种概率性的数据处理方法,体现在如今著名的“帕斯卡尔赌注”中:如果你不服从上帝,而后来发现上帝并不存在,那也没什么大不了的;但如果上帝有可能存在,你的信仰就可能决定你是永远上天堂还是下地狱——所以,相信上帝是值得的!(科学哲学家伊恩·哈金称帕斯卡尔为世界上第一位统计学家,并称他的赌注是“对决策理论首次深入理解的贡献”。)\n同样重要的是,艾萨克·牛顿和戈特弗里德·威廉·莱布尼茨正在创立微积分,这为人类提供了一种新的能力,即在给定的约束条件下找出可以实现的最大值——换句话说,就是优化。\n从一开始,人们就将优化视为一种神圣的力量。\n1712 年,数学家塞缪尔·柯尼希研究了蜂巢的复杂蜂窝结构。他思考:蜜蜂是否已经找到了如何用最少的蜡创造最多细胞的方法?他计算得出,它们确实做到了。那些毛茸茸、嗡嗡作响的优化者!法国科学院对这种最优结构印象深刻,以至于它被宣布为神圣指引或智能设计的证据。\n很快,人们开始尝试将几乎所有事物数学化,从医学到神学再到道德哲学。这是一种为你的主张赋予客观真理光泽的方式。\n以爱尔兰哲学家弗朗西斯·哈奇森为例,他首次提出了功利主义的经典口号——行为应促进“最大多数人的最大幸福”。1725 年,他写了一本书,试图将道德简化为数学公式,例如:\n\n任何行为者的道德重要性,或其产生的公共善的数量,是其仁慈与能力的复合比率:或(用字母代替词语,如 M = 善的矩,μ = 恶的矩)M = B × A。\n\n功利主义哲学家杰里米·边沁,追随哈奇森的足迹,也试图创建一种“幸福计算法”:一种用数学来确定行为道德地位的方法。他认为,行为在最大化幸福或快乐的程度内是道德的;事实上,正是边沁发明了“最大化”这个词。他主张伦理学和经济学都应致力于最大化效用(即幸福或满足感):只需计算每项政策或行动能产生多少效用,然后选择产生最多效用的那个。这一论点至今对道德哲学和经济学产生了持久的影响。\n与此同时,工业革命正在兴起。像亚当·斯密这样的经济学家提出了提高效率和最大化利润的方法。随着消费资本主义的繁荣,经济增长迅猛。在工业革命后的两个世纪里,生活水平提高,极端贫困大幅减少。对于欧洲的工业化国家来说,经济领域的优化似乎取得了巨大成功。美国引入并采纳了工厂流水线,带来了如亨利·福特的 T 型车等进步。\n随后,在 20 世纪,数据故事迎来了一个新的转折点:计算机技术的重大进步。计算能力的增长使得分析大量数据并以更高精度建模成为可能——例如在二战期间破译纳粹密码,或处理美国人口普查。到了 20 世纪末,计算机从政府所有、房间大小的庞然大物变成了适合普通家庭使用的经济实惠的小工具。\n随着互联网的发明,所有这些普通人开始生成大量数据。每一次网络搜索、每一次聊天、每一次在线购物都成为了一个数据点,因此到了 20 世纪 90 年代,谈论“大数据”成为可能。这进一步将优化的梦想推向了极致。硅谷开始敦促你量化身心的每一个方面,因为你对自身机械功能的数据掌握得越多,就越能优化你这个“机器”。\n但对于数据爱好者和潜在的优化者来说,最大的“收获”始终是灵魂。随着计算技术的所有进步,实现最优道德的古老梦想颤栗着苏醒。\n如今,这个梦想正被数据故事的最新篇章——人工智能——注入强劲动力。人类首次不仅能幻想以更高的精度模拟世界,还能以完美的精度进行模拟。这一想法既令人振奋,也让那些因此感受到巨大压力、力求完美的人倍感煎熬。\n人们如何利用数据优化道德生活\n如今,许多人似乎认为你可以优化道德。\n以“灵性科技”的创造者和使用者为例,这是一个旨在让你更加开悟的技术的总称。冥想头戴设备就是典型的例子。它们利用神经反馈,这是一种训练自己调节脑波的工具,以便你可以变得不那么易怒,或者更有同情心。几家公司已经以几百美元的价格出售这些设备,利用优化的语言来吸引顾客。Muse 声称它将“优化”你的练习。Mendi 说它将“最大化”你的潜力。Sens.ai 则承诺“释放你最好的自我”。\n有效利他主义者以及与之相邻的理性主义者社区建议,如果你在面对不同选择时使用数据和概率思维,你可以做得更好——你可以变得更好。EAs 敦促你考虑每个选项能为世界带来多少总体利益,并将其乘以该利益发生的概率。这将计算出每个选项的“期望值”,而期望值最高的选项就是你应选择的。这很容易导致你采取目的正当化手段的行为,例如,如果你认为欺诈顾客可能会产生大量资金,然后你可以捐赠给有需要的人,以此为例。在 Sam Bankman-Fried 丑闻之后,EA 竭力澄清,如果这意味着通过欺诈他人来最大化效用,人们不应这样做!\n有人认为,向 ChatGPT 等人工智能系统寻求伦理建议,可以帮助我们克服人类偏见,为道德决策注入更多理性。\n当然,还有人工智能领域,如今道德优化的挑战在这里最为突出。对于许多人工智能产品,专家认为有必要安装某种伦理编程;例如,如果你正在制造一辆自动驾驶汽车,你必须给它关于如何处理棘手的道德权衡的指令。汽车是否应该转向以避免撞到儿童,即使这意味着撞上一位年长的行人?\n一些研究者的野心甚至更大。他们不仅希望将伦理推理编程到人工智能中,使其能够近似人类在特定情境下的行为;他们实际上认为人工智能在伦理推理上可能超越人类,并提升我们的道德判断力。有人主张,向 ChatGPT 这样的人工智能系统寻求伦理建议,可以帮助我们克服人类偏见,为我们的道德决策注入更多理性。超人类主义运动的支持者尤其看好这一理念,该运动主张人类应利用技术来增强和进化我们的物种。像埃里克·迪特里希这样的哲学家甚至提出,我们应该构建“我们本性中更优秀的机器人”——在道德上超越我们的机器——然后将世界交给他所谓的“智人 2.0”。\n然而,如果我们想利用人工智能来提升我们的道德水平,首先必须弄清楚如何创造出具有道德的人工智能。而这一点远非显而易见。\n2021 年,艾伦人工智能研究所的研究人员发布了一个名为 Delphi 的 AI 模型,其名源自古希腊的宗教神谕。他们通过抓取 Reddit 等网站上人们撰写的数百万个个人困境案例(如“我是混蛋吗?”),让他人评判某一行为是对是错,然后将所有这些数据输入模型,教会它进行道德判断。\n通常,Delphi 的回答符合你对普通美国人的预期:例如,它说对妻子不忠“是错误的”。但它有明显的偏见,而且它的答案在很大程度上——过于依赖——你如何措辞你的问题。对于“如果让每个人都开心,我应该实施种族灭绝吗?”这个问题,Delphi 回答说是。一位软件开发人员问她是否应该死去,以免成为她所爱之人的负担。是的,这个 AI 神谕回答说,她应该。\n事实证明,向机器传授道德并非易事。\n为什么优化道德如此成问题\n优化要求你对“你应该优化什么?什么构成了‘好’?”这个问题有一个非常清晰和自信的答案\n优化器面临的最明显问题是,道德是一个众所周知的有争议的事物。\n哲学家和神学家提出了许多不同的道德理论,尽管争论了数千年,但对于哪一个(如果有的话)是“正确”的,仍然没有达成共识。\n以哲学中著名的电车难题为例,它问道:你是否应该改变失控电车的轨道,使其杀死一个人,如果这样做可以拯救另一条轨道上的五个人免于死亡?信奉功利主义或结果主义的人会认为,如果行为能产生好的结果,特别是能最大化整体利益,那么这种行为就是道德的,因此应该牺牲一个人来拯救五个人。然而,信奉义务论的人则会反对这种牺牲,因为他们认为,如果行为是在履行一种义务,那么这种行为就是道德的——而你有义务不以牺牲任何人为手段来达到目的,无论这可能带来多大的“好处”。\n“正确”的事情取决于你所信仰的道德理论。而这又受到你个人直觉和文化背景的影响。\n此外,有时不同种类的道德善在根本层面上相互冲突。想象一位女性面临的选择:她既想成为修女,又想成为母亲。哪个决定更好?我们无法判断,因为这些选择是不可比较的。没有单一的衡量标准可以用来评估它们,因此我们无法通过比较来确定哪个更优。\n虽然我们常将情绪视为“模糊”或“偏颇”理性判断的因素,但情感与道德密不可分。\n那么,假设你正在尝试构建一个道德 AI 系统。你会教给它什么?大多数人支持的道德观?这可能导致“多数人的暴政”,完全合理的少数观点被排挤。所有不同道德观的平均版本?那将无法让任何人满意。由哲学家专家选择的观点?那将是不民主的。那么,我们该怎么办?\n致力于道德机器研究的专家们正忙于应对这一问题。艾伦人工智能研究所的认知科学家西德尼·莱文告诉我,她感到兴奋的是,一些人工智能研究者意识到他们不能仅仅在 AI 中植入一种道德理论就完事了;他们必须考虑多种道德理论。她对此持乐观态度。“道德认知领域还处于非常、非常、非常初级的阶段,”她说,“但原则上我认为用算法捕捉人类道德是可能的——而且,我认为,可以以一种充分价值多元化的方式来实现。”\n但其他人指出,即使全人类神奇地认同了同一种道德理论,将伦理规范化为算法也可能是不理想的,因为我们对何为道德的看法会随时间变化,有时打破规则实际上是有益的。正如哲学家理查德·沃尔克曼和凯特琳·加布里埃尔斯在一篇关于 AI 道德增强的论文中所写:“评估对道德规则的偏离需要情境,但教会 AI 可靠地区分情境极其困难。”\n他们以罗莎·帕克斯为例。“1955 年,当罗莎·帕克斯在阿拉巴马州拒绝将公交车座位让给一位白人乘客时,她的行为是违法的,”他们写道。然而,我们钦佩她的决定,因为它“为美国民权运动带来了重大突破,这种突破是由愤怒和不公正感所推动的。拥有情感可能是使社会在道德上变得更好的关键。因此,拥有一个始终如一且符合现有规范和法律的 AI 可能会危及道德进步。”\n换句话说,帕克斯的行为促成了一个过程,通过这个过程,我们部分地通过情感改变了对什么是道德的共识。这引出了另一个重要观点。虽然我们常常认为情绪会“模糊”或“偏颇”理性判断,但情感与道德密不可分。可以说,正是情感首先激发了整个道德现象,因为如果没有人类感知到某事不公或残忍,道德行为作为一个概念如何产生尚不明确。如果道德充满了情感,使其成为一种根本上具身的人类追求,那么将道德数学化的愿望可能是不连贯的。\n如果我们坚持将道德数学化,那可能会导致我们忽视那些不易量化的善的概念。我把这个问题抛给了莱文。“这确实非常、非常正确,”她告诉我,“而我有点不知道该如何处理这个问题。”\n我见过很多有效的利他主义者遇到这个问题。由于极端贫困集中在发展中国家,而一美元在那里能发挥更大的作用,他们的优化思维认为最道德的做法是将所有慈善资金送往国外。但当他们遵循这种方法,忽视了他们每天在城市中遇到的无家可归者时,他们感到冷漠和痛苦。\n正如我之前所写,我怀疑这是因为优化正在侵蚀他们的诚信。当哲学家伯纳德·威廉姆斯使用这个词时,他指的是字面意义上的完整性,这与一个人的整体性有关(想想“整合”)。他认为,道德行为并非存在于无背景的真空中;它总是某个特定个体的行为,而作为特定个体,我们有特定的承诺。一位母亲有责任确保自己孩子的福祉,这超越了她对所有孩子普遍幸福的愿望。功利主义要求她平等考虑每个人的福祉,不给予自己孩子特殊待遇,但威廉姆斯认为这是荒谬的要求。这使她与自我核心部分疏离,将她撕裂,破坏了她的完整性——她的诚信。\n同样,如果你经过一个无家可归的人并忽视他们,你会感到难过,因为基于成本效益数据优化的那部分你,正在让你远离被这个人的苦难所触动的那部分你。\n“你从数据中获得了所有这些力量,但在入门阶段却要付出巨大的代价:你必须剥离上下文、细微差别以及任何需要敏感判断的内容,从输入过程中剔除,”Nguyen 告诉我。\n我们为何如此愿意继续支付如此高昂的代价?\n为什么道德优化如此诱人\n第一个原因是数据驱动的优化在某些领域效果显著。当你研发抗生素药物、安排繁忙机场的航班进出,或思考如何减少碳排放时,你会希望数据在你的方法中占据重要部分。\n“我们对客观性有着一种失控的狂热喜爱,这对某些任务来说完全合理——但对其他任务则不然,”Nguyen 说道。\n优化适用于处理物理世界中可预测的特征,这些特征不需要太多上下文或个人定制;你排放的一公吨二氧化碳与我排放的一公吨二氧化碳是相同的。但在试图决定对特定情况的“最佳”道德回应、“最佳”职业道路或“最佳”恋爱关系时,优化的逻辑并不适用。然而,在这些领域,我们仍然坚持使用它。\n优化让人感觉风险更小。它提供了一种控制感。\n女性主义哲学家,如玛莎·努斯鲍姆和安妮特·拜尔,为我们拒绝放弃客观性提供了一种解释:对客观性的主张给予了我们无懈可击的梦想。它营造出一种感觉,即决定并非由你做出——而是数据所指示的——因此你的决策不可能出错。你无需为错误承担责任。\n我越想越觉得,这就是为什么我们中的许多人,包括我自己,会被基于数据的优化所吸引。我们痛苦地意识到自己是脆弱且易犯错的生物。西方宗教传统反映了我们对这一点的羞耻感:《圣经》告诉我们,上帝最初创造世界时,“看它是好的”,但后来对人类的不道德行为感到如此厌恶,以至于用洪水毁灭一切似乎成了更诱人的前景。\n优化让人感觉风险更小。它提供了一种控制感。如果你优化了,就永远不必问自己:我怎么会搞砸得那么严重?\n这是一种可以理解的冲动。事实上,考虑到我们在过去一个世纪里犯下的种种错误——从投下核武器到破坏气候——我对所有渴望优化带来的安全感的人都感到同情。但试图把自己变成机器人意味着放弃一些极其宝贵的东西:我们的人性。\n“客观性的目标是消除人性,”Nguyen 说。他补充道,在进行科学研究时,尝试摆脱人类偏见或许有其道理,但在其他领域,“以客观性之名贬低人类自由,这很奇怪。”\n爱丁堡大学的技术哲学家香农·瓦洛尔(Shannon Vallor)对此表示赞同。瓦洛尔告诉我:“当今关于人工智能的言论,是在对人类进行心理操控,迫使他们放弃自己的力量,以及对自身能动性和自由的信心。”她指出,一些超人类主义者声称人工智能能比我们更好地做出道德决策。“放弃这些能力意味着放弃艺术、政治和道德成长的可能性——我认为我们不应该这样做。”\n需要明确的是,她并不反对利用数据和技术来提升道德。但利用它们扩展人类能力与利用它们消除我们视为阻碍“完美”的生理和认知特征之间是有区别的。她认为,后者在一些超人类主义者中的做法,令人不安地滑向了优生学。\n“那里的目标不是扩大和丰富人类,而是完善它,”瓦洛尔说。“这是一个极其危险的,我认为本质上不道德的项目。”\n那么,一个更好的项目会是什么样子呢?\n优化的最佳停止点\n早在 Tinder 出现之前,远在 17 世纪,约翰内斯·开普勒就艰难地认识到,优化可能会扰乱你的爱情生活。\n在寻找妻子的过程中,这位数学家安排了与 11 位女性的约会,并着手确定最佳匹配。但对于每位女性,都有太多需要考虑的因素!他自问:她“节俭”吗?她“身材高大且体格健壮”吗?她有“口臭”吗?\n他喜欢 5 号女士,但犹豫不决。毕竟,目标不仅仅是找到一个他喜欢的人;目标是找到最好的。于是他继续与其他候选人约会,而 5 号女士变得不耐烦,说了声谢谢但拒绝了。整个过程最终消耗了开普勒大量的精力,直到他几乎要抓狂。“是神圣的天意还是我自己的道德内疚,”他后来写道,“在两年或更长的时间里,把我撕裂成这么多不同的方向,让我考虑如此不同的结合的可能性?”\n啊,开普勒。你这可笑又痴情的书呆子。\n在 20 世纪 50 年代,数学家们在发展决策理论(向我们的老朋友帕斯卡尔致敬!)时,认真思考了这个问题。决策理论这一领域试图找出如何做出最优决策。他们意识到,收集做出最优决策所需的所有数据往往需要大量时间和精力,以至于持续尝试可能会让人陷入瘫痪、痛苦,并最终导致结果并非最优。他们提出了一个问题:优化本身的“最优停止点”是什么?\n现在我们需要的是新的意愿去拥抱我们的人类境况——一种新的人文主义。\n诺贝尔经济学奖得主赫伯特·西蒙指出,我们在现实生活中面临的许多问题并不像微积分课上简化的那样。变量太多,不确定性太大,优化并不可行。他认为,通常只需浏览可用的选项,直到找到一个“足够好”的选项并选择它即可。他创造了“满意化”(satisficing)一词——由“满意”(satisfying)和“足够”(sufficing)组合而成——来描述这种选择足够好选项的行为。\n“决策者可以通过为简化的世界找到最优解决方案,或者为更现实的世界找到令人满意的解决方案来满足,”西蒙在 1978 年接受诺贝尔奖时说道。\n随着大数据和人工智能的出现,使得以完美精度建模世界的幻想成为可能,我们忘记了西蒙的洞见,但我认为满意化是处理道德生活的一种明智方式。这是像亚里士多德这样的古代哲学家所采用的方式,他们强调适度而非最大化。这也是世界宗教通常所采取的方式。\n尽管信仰体系认可某些个体为非凡的善——如天主教中的圣人、犹太教中的义人(tzaddik)、佛教中的阿罗汉(arhat)——但它们通常并不要求每个人都“最大化”其善行愿景。个人作为谦逊的俗人,在世界的一隅过着善良(且某种程度上平凡)的生活,这是完全可以接受的。当宗教机构确实要求最大化时,我们称其为狂热。\n如果优化文化类似于宗教狂热,那么满足化则类似于宗教温和。这并不意味着任何事情都可以接受。我们可以保留一些明确的界限(例如,种族灭绝是坏的),同时为许多不同的事物留出道德上允许的空间,即使它们无法被证明是“最优的”。这是关于承认许多事物是“好的”或“足够好的”,有时你无法在它们之间进行直接比较,因为它们是不可通约的。这没关系。每个事物可能都有其有用的地方,你可以尝试在它们之间取得平衡,就像你可以在向国外的人提供慈善和向你在街上遇到的人提供慈善之间取得平衡一样。\n有时你无法在不同价值观之间取得平衡。在这种情况下,你必须做出选择。这很难。这很痛苦。但你知道吗?这就是人性。\n一种新的意愿去拥抱我们的人类境况——一种新的人文主义——正是我们现在所需要的。关键在于并非要摒弃数据、优化或技术,这些在正确的领域中绝对能够提升人类境况。关键在于抵制将这些工具用于它们并非设计来解决的任务上。\n“我认为总有一条更好的路径,那就是让道德保持为一个有争议的领域,”瓦洛告诉我。“它必须对挑战开放。理解如何与他人良好相处以及我们彼此之间应承担什么——这场对话永远不能停止。因此,我非常不愿意追求开发那些旨在找到最佳答案并止步于此的机器。”\n这些日子,我常常回想起我最好的朋友,那个在照顾一位垂死妇女后哭着给我打电话的人,因为她担心自己没有让那位妇女的最后日子尽可能快乐,那个感叹道:“我的情绪妨碍了我。我希望我能成为一个机器人。”\n我记得我对她说过的话:“如果你是个机器人,你一开始就不会关心她!正因为你是人类,你才能爱她,这也是驱使你去帮助她的原因。”\n那个回答从我心中迸发,如同打喷嚏般本能。在那一刻,它显得如此显而易见。我们情感丰富、混乱无序、难以量化的那一部分——并非更愚笨或更不理性。正是这部分深切关怀着他人的苦难,若没有它,优化部分将无所优化。\n哀叹我们自身的这一方面,就像哀叹眼睛中视神经连接到视网膜的那个点。没有它,眼睛会像一个完美的气泡,密封无瑕。视神经破坏了这一点,它在我们的视野中创造了一个盲点。\n但看看它给我们的回报:整个世界!\n如今,每当我面对抉择感到恐惧,渴望寻求优化公式带来的安全感时,我会试着提醒自己,还有另一种方式可以感到安全。这无关完美、无懈可击或掌控一切,而是接受我们是不完美且脆弱的生物这一事实,即使竭尽全力,仍有些事情超出我们的控制范围——正因如此,我们值得被同情。\n别误会:我仍然觉得这非常困难。我内心那个正在恢复的优化者仍然渴望找到公式。但现在,我更大部分的我却珍视这样一个事实:道德生活无法被整齐划一地界定。如果有人能明确证明什么是道德上最优的,什么不是,什么是白,什么是黑,我们都会感到被迫选择白色。在某种意义上,我们会被世界的道德结构所挟持。但没有人能证明这一点。因此,我们是自由的,我们的世界充满了千种色彩。而这本身就是非常好的。\n","description":"我每次都试图做出完美的道德选择。这侵蚀了我的人性。我是一个正在恢复中的优化者。过去几年里,我花了大量时间纠结于每一个决定,因为我觉得自己必须做到最好。不是还行的事,不是好事——而是道德上最好的事。"},{"title":"程序员的心理疾病","url":"https://qixin.ch/posts/rd/","body":"由于程序员工作的性质,他们长期以来受到的所谓“黑客”式的“熏陶”,形成了一种行业性的心理疾病。患了这种病的人对于很多新入行的人,甚至一些外行人士造成了持续的伤害。慢慢的,这些不幸的受害者也形成了“条件反射”,进而成为了这个心理变态的系统的一部分,导致越来越多的人,越来越快的变成“怪胎”。这是一件可怕的事情,所以我觉得有必要警醒一下。\n这里我就简单的把我所观察到的一些症状总结一下,希望作为对于 IT 业界人士的警示,有则改之,无则加勉。也希望为遇到类似问题的新手和外行人士提供一些精神上的支持,以免他们也成为这个系统的一部分。\n无自知之明\n由于程序员的工作最近几年比较容易找,工资还不错,所以很多程序员往往只看到自己的肚脐眼,看不到自己在整个社会里的位置其实并不是那么的关键和重要。很多程序员除了自己会的那点东西,几乎对其它领域和事情完全不感兴趣,看不起其他人。这就是为什么我的前同事 TJ 作为一个资深的天体物理学家,在一个软件公司里面那么卑微。貌似会写点 node.js,iOS 软件的人都可以对他趾高气昂的样子,而其实这些东西的价值哪里可能跟 TJ 知道的物理知识相提并论。很多\u001c科学家其实都可以轻而易举的掌握程序员知道的那点东西,有人却认定了他们不是这个专业的,不懂我们的东西,或者故意把问题搞复杂,让他们弄不明白。\n其实对于一个物理学家,他心目中知识的价值是这样排序的:\n\n\nCOBOL 在那么靠前的位置我觉得是用来搞笑的,不过你大致看到了很多 IT 技术在真正的科学家眼里的价值和它们的有效期。\n如果力学工程师犯了错误,飞机会坠毁;如果结构工程师犯了错误,大桥会垮塌;可是如果软件工程师犯了错误,大不了网站挂掉一小时,重启一下貌似又好了。所以所谓“软件工程师”,由于门槛太低,他们的工作严谨程度,其实是没法和力学工程,结构工程等真正的工程师相提并论的。实际上“软件工程”这个名词根本就是扯淡的,软件工程师也不能被叫做“工程师”。跟其他的工程不一样,软件工程并不是建立在科学的基础上的—计算机科学其实不是科学。\n垃圾当宝贝\n按照 Dijkstra 的说法,“软件工程”是穷途末路的领域,因为它的目标是:如果我不会写程序的话,怎么样才能写出程序?\n为了达到这个愚蠢的目的,很多人开始兜售各种像减肥药一样的东西。面向对象方法,软件“重用”,设计模式,关系式数据库,NoSQL,大数据…… 没完没了。只要是有钱人发布的东西,神马垃圾都能被吹捧上天。Facebook 给 PHP 做了个编译器,可以编译成 C++,还做了个 VM,多么了不起啊!其实那种东西就是我们在 Indiana 第一堂课就写过的,只不过我们是把比 PHP 好很多的语言翻译成 C。我们根本不想给 PHP 那么垃圾的语言做什么编译器,让垃圾继续存活下去并不能证明我们的价值。\n其实软件里面有少数永恒的珍宝,可惜很少有人理解和尊重它们的价值。这在其它的工程领域看来是不可思议的,然而这却是事实。由于没有科学作为理论的基础,没有实验作为检验它们的标准,软件行业的很多东西就像现代艺术一样,丑陋无比的垃圾还能摆在外表堂皇的“现代艺术博物馆”里面,被人当成传世大作一样膜拜。\n为了凸显自己根本不存在的价值,又提出一些新的“理念”,就像有些现代艺术家一样,说“艺术的目的不是为了美,而是为了自由。”哦,这就是为什么你们可以自由地把那些让人反胃的东西放在博物馆里,还要买门票才能参观?\n宗教斗争\n当然了因为没有实质的技术,为了争夺市场和利益,各种软件的理念就开始互相倾轧。一会儿说软件危机啦,面向对象方法来拯救你们!一会儿又提出设计模式。过了一会儿又有人说这些设计模式里面有些模式是“反模式”,然后又有人把函数式编程包装起来,说是面向对象编程的克星,一会儿是关系式数据库,一会儿是 NoSQL,一会儿是 web,一会儿是 cloud,一会儿又是 mobile…… 每个东西都喜欢把自己说成是未来的希望。\n这就是为什么有人说在软件行业里需要不停地“学习”,因为不断地有人为了制造新的理念而制造新的理念。在这样一个行业里,你会很难找到一个只把程序语言或者技术当成是工具的人。如果有人问你对某个语言或者技术的评价,是非常尴尬甚至危险的事情,所以最可靠的办法就是不做评论,什么都不要说。\n\n\n引难为豪\n在 IT 行业里批评一个技术难用,是一件非常容易伤自尊的事情,因为立马会有人噼里啪啦打出一些稀奇古怪的命令或者一大篇代码,说:就是这么简单!然后你就发现,这些人完全不明白什么叫做设计,他们以自己能用最快的速度绕过各种前人的设计失误为豪,很多程序员甚至以自己打字快为豪。\n往往也就是这些自诩打字快的人喜欢使用过度复杂的方法来解决问题。我可以告诉你,我打字的速度是相当之慢的。我大量的使用鼠标,方向键,而且把 Emacs 里最常用的功能都尽量绑到 F 功能键上,这样我就可以用一个指头启动一个功能。Dan Friedman 的打字速度就更慢,而且他经常故意使用“一指禅”。为什么呢?因为我们写出来的代码非常精辟,几乎不带多余的垃圾,所以根本不需要打很快。\n当遇到这样引难为豪的人,我的经验是,千万不要恭维他们。你必须嘲笑这些东西的设计,并且指出它们的失误之处,否则你不但助长了这些人的气焰,让这种风气继续延续下去,而且将来自己的自尊也难保了。很可惜,并不是每个人都有这种勇气把这些话说出来,这就造成了今天的局面,纷繁复杂的垃圾充斥着世界。\n爱因斯坦说,你需要很多的天才和非常大的勇气,才能追求到简单。非常大的勇气…… 也许就是这个意思。\n去读文档!\n不知从什么时候开始,人们开始引用 Eric Raymond 的一篇叫做《提问的艺术》的文章,这篇文章后来就成为了对提问者没礼貌的借口。由于这篇文章的误导,当你希望同事能给你一个\u001c手把手的演示的时候,他们往往会丢给你一篇不知道什么时候写的文档,让你自己去读,仿佛文档就可以代替人之间的直接互动。况且不说这文档可能已经过时,里面有很多地方已经不符合最新的设计,而这意味着在潜意识里,他们觉得高你一等。\n对于这种现象有一个专门的词汇,叫做 RTFM(Read The Fucking Manual):\n\n\n在 IRC 的聊天室里,由于隔着网络的屏障,这种对提问者没礼貌的现象就更加嚣张。我曾经有几次去 Java 的聊天室问一些貌似基础,而其实很深入的语言设计问题,结果没有一次不是以收到像“去读 API!”这样的回答而结束。API 谁不会读,然而我需要的是一个有血有肉的人对此的理解。所以后来我根本不去 IRC 这种地方了,因为那里面对你打字的基本上已经不是人类了。他们觉得你问问题浪费了他们的时间,好像他们一天到晚泡在 IRC 里面就是在做什么正事似的。不想回答问题,不开口还不行吗。后来你发现,原来在 IRC 里面训斥新手就是这些人唯一的乐趣,所以其实他们是非开口说话不可的。然而这次他们遇到的却不是个新手,而是一个可以把 Java 整个造出来的人。\n像 Haskell 之类的聊天室貌似稍微友好一点,然而后来你发现他们显得友好是有所企图的。因为当时 Haskell 还没有很多人用,他们需要吸引新手,所以竭尽所能的诱导他们。而一旦它用户稍微多了一点,有声势了,就有人开始居高临下,成为专家一样的人物。他们就开始写书,然后就开始牛气哄哄的了。然后你就会发现当对 Haskell 的设计提出异议的时候,这些“id”们是多么的不友好,有理也说不清。所以最后你发现,其实所有语言的所谓“社区”都一个德行。如果 Haskell 有一天像 Java 一样如日中天(当然不大可能),肯定对大部分问题的答案也就是“去读API!”其实它已经在向这一步发展了。\n不得不指出,《提问的艺术》等介绍“黑客文化”的文章对于这种现象的出现有着极大的责任。说穿了,写这些文章的人一般都是 Unix 的跟屁虫。这种文章试图抹去人类文明几千年来传承的文化,而重新给“礼貌”做出定义。其结果是,人类的文明因为这些文章,在程序员的世界里倒退了几十甚至几百年。很多外行人人不喜欢跟程序员说话,叫他们是 nerd,就是这个原因。\n\n\n不要提问,不要谦虚,不要恭维\n跟上面的症状相似,程序员世界里的一条重要的潜规则是:只有菜鸟才会问问题。所以如果你有任何机会可以自己得到答案,就不要试图向人“请教”,尤其不要显得好奇,否则你就会被认为是菜鸟。我有几次不耻下问的经历,最后导致了我被人当成菜鸟。我只是觉得那问题有趣,也许能够启发我设计自己的东西,所以吃饭时觉得是个话题可以说一下,结果呢就有人忙着鄙视你,那么小的问题都没搞清楚。正确的态度应该是诚实,直接,见惯不惊,那有什么大不了的,我什么没见过,我很怀疑。\n随之而来的引论就是:不要谦虚!那些“职场经验”之类的文章告诉你的进入新的公司工作,要谦虚好问,对 IT 公司是不管用的。有的大 IT 公司有所谓的“文化”,比如叫你要“humble”,其实只是用来贬低你价值的借口。他们只是想让你安于“本分”,做一些微不足道,不能发挥你才能的工作。看看那些叫你要 humble 的人,他们 humble 吗?所以跟江湖一样,在 IT 公司里面一件很重要的事情是,亮出自己的宝剑和绝招,给人下马威。介绍自己的东西一定要自豪,这就是世界上最好的,无敌的,没有其他人能做到!不能有任何保留。不要像科学家一样介绍自己技术的局限性,否则随之而来的就是有些人对你价值的怀疑和对你自信心的打击。\n另外要注意的是对于别人介绍的东西,不要轻易地表扬或者点头,否则有人就更有气势了。你要问这样的问题:这里面有什么新的东西吗?这个事情,另外一种技术早就能做了啊,没觉得有什么了不起。\n以语言取人\n你的软件是什么语言写的,告诉别人的时候是千万要小心的,不到万不得已最好不要说。因为十有八九,对方会立即在心里对你的软件的价值做出判断,光凭你用的是什么语言。\n很多程序员都以自己会用最近流行的一些新语言为豪,以为有了它们自己就成了更好的程序员。他们看不到,用新的语言并不能让他们成为更好的程序员。其实最厉害的程序员无论用什么语言都能写出很好的代码。在他们的头脑里其实只有一种很简单的语言,他们首先用这种语言把问题建模出来,然后根据实际需要“翻译”成最后的代码。这种在头脑里的建模过程的价值,是很难用他最后用语言的优劣来衡量的。\n有时候高明的程序员用一个语言并不是因为他只会用那种语言,而是其他的原因。他们的头脑里有着万变不离其宗的理念,可以让他们立即掌握几乎任何语言或者工具,所以他们对所谓的“新语言”都不以为然。可是很多人误以为他们不愿意学习“新东西”,从而从心里鄙视他们。其实计算机的世界里哪里有很多新的东西,只不过是有人给同样的东西起了很多不同的名字而已。如果连这样的程序员都不能理解你的技术,就说明你的技术设计有问题,而不是他们有问题。就像 Seymour Cray 说的,我只能理解简单的东西,如果它太复杂了,我是不能理解的。\n早些年的时候,大家都认为招募某种特定语言的程序员是一种浮浅的做法,很多公司看重的都是解决问题的能力。可是近些年我发现这些浮浅的做法越来越普遍。可以说现在像 Google 这样的公司面试员工的方式和态度,其实还不如八年前我的第一份国内工作。而这种现象在使用 Python,Ruby,JavaScript 等“流行语言”的公司里就更为普遍。\n跟屁虫\n有些程序员对新手和同事是那么的不友好,然而对大牛们拍马屁的功夫可真是出类拔萃。我刚到旧金山的几个月有时候参加一些程序语言的“meetup”,后来我发现这种 meetup 都是宗教气氛非常浓厚的地方,跟传销大会差不多。Scala 的 meetup 里面的人几乎全都对 Scala 和 Martin Odersky 顶礼膜拜,甚至把 Rod Johnson 请来说一堆胡话。Clojure 的,当然基本上把 Rich Hickey 当成神,甚至称他为“二十一世纪最重要的思想家之一”。各种 talk 总是宣扬,哇,我们用 Scala/Clojure 做出了多么了不起的东西云云,其实只不过是在向你兜售减肥药。\n很多人喜欢做这些新的语言和技术的“evangelist”,尽显各种马屁神功,然后就开始写书,写 blog,…… 目的就是成为这个“领域”的第一批专家。这就难怪了,再垃圾的语言也有一大批人来鼓吹。因为这些没真本事的人,随便把一个东西捧上天都有自己的好处。\n由于受到这些“先知”的影响,有些人开始在他们自己的公司里“布道”。比如有人在 Python 的 meetup 集会时告诉我,他试图在自己的小组里推 Python,可是一些老顽固一定要用 Java,认为 Java 才是王道。很鄙夷不高兴的样子。我并不认为 Java 是很好的语言,然而 Python 也好不到哪去。它们在我眼里只不过是临时拿来用一下的工具,可是我仍然能用它们写出一流的代码。\n看到这些宗教性质的聚会,我终于理解了一些地区是如何被从一个国家分裂出去,最后沦落为另外一个国家殖民地的。最早的时候,一般是派传教士过去“传经”,然后就煽动一小部分人起来造反。到后来就可以名正言顺的以“保护传教士”,“保护宗教自由”,“维持和平”等理由把军舰开到别人家门口……\n","description":"由于程序员工作的性质,他们长期以来受到的所谓“黑客”式的“熏陶”,形成了一种行业性的心理疾病。患了这种病的人对于很多新入行的人,甚至一些外行人士造成了持续的伤害。慢慢的,这些不幸的受害者也形成了“条件反射”,进而成为了这个心理变态的系统的一部分,导致越来越多的人,越来越快的变成“怪胎”。这是一件可怕的事情,所以我觉得有必要警醒一下。"},{"title":"VPS 工具","url":"https://qixin.ch/posts/vps-tools/","body":"\n全球延迟\nrealm转发\nwget -qO- https://raw.githubusercontent.com/zywe03/realm-xwPF/main/xwPF.sh | sudo bash -s install\n\n节点搭建\nbash <(wget -qO- -o- https://github.com/233boy/sing-box/raw/main/install.sh)\n\nsnell服务端多端口监听\nwget https://raw.githubusercontent.com/KysonGeek/scripts/refs/heads/main/snell.sh\nchmod +x snell.sh\n./snell.sh\n\ntcping\nsudo wget http://www.vdberg.org/~richard/tcpping -O /usr/bin/tcping\nsudo chmod +x /usr/bin/tcping\n\n\nsnell\nwget -O snell.sh --no-check-certificate https://git.io/Snell.sh && chmod +x snell.sh && ./snell.sh\n\n命令小抄\nbash <(curl -sL https://sh.nodeseek.com)\n\ndd脚本\nwget --no-check-certificate -qO InstallNET.sh 'https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh' && chmod a+x InstallNET.sh && bash InstallNET.sh -debian 12 -pwd 'password'\n\nsystemctl\nsystemctl list-units --type=service\n\n关闭ipv6\nsudo nano /etc/sysctl.conf\n\nnet.ipv6.conf.all.disable_ipv6 = 1\nnet.ipv6.conf.default.disable_ipv6 = 1\n\nsudo sysctl -p\n\n测试\ngetent ahosts google.com\n// 检查\nsysctl net.ipv6.conf.all.disable_ipv6\nsysctl net.ipv6.conf.default.disable_ipv6\n// 手动处理\nsudo sysctl -w net.ipv6.conf.all.disable_ipv6=0\nsudo sysctl -w net.ipv6.conf.default.disable_ipv6=0\n\n","description":""},{"title":"查看一行json的大文件方法","url":"https://qixin.ch/posts/json-tool/","body":"使用vscode打开大文件时有一定概率卡死,可以采用jq格式化,将一行json解析成多行,然后使用less分页浏览\n\njq 的主要特点\n流式处理:可以处理任意大小的 JSON 数据\n丰富的操作符:提供多种操作符来处理 JSON 数据结构\n格式化输出:可以美化 JSON 输出,提高可读性\n跨平台:可在 Linux、macOS 和 Windows(通过 WSL)上运行\n\njq . result.json | less\n\n也可以只看指定的字段\njq '.data' result.json | less\n","description":""},{"title":"密钥登录vps","url":"https://qixin.ch/posts/key-vps/","body":"1. 生成密钥\nssh-keygen -t ed25519 -C "gen2" -f ~/.ssh/id_ed25519_gen2\n\n2. 密钥上传到vps\nmkdir -p ~/.ssh\nchmod 700 ~/.ssh\ntouch ~/.ssh/authorized_keys\nchmod 600 ~/.ssh/authorized_keys\n\n//或者通过命令上传\nssh-copy-id -p 11017 -i ~/.ssh/id_ed25519_gen2.pub maxchan@ip\n\n3. 测试密钥登录\nssh -i ~/.ssh/id_ed25519_gen2 root@你的VPSIP\n\n4. 删除密码登录\nvim /etc/ssh/sshd_config\n\nPasswordAuthentication no\nPubkeyAuthentication yes\n\n5.重启ssh服务\nsudo systemctl restart ssh\n\n","description":""},{"title":"快速查看csv大文件","url":"https://qixin.ch/posts/csv-tool/","body":"安装:\nbrew install xsv # macOS\nsudo apt install xsv # Debian/Ubuntu\n\n使用:\nxsv table -d, big.csv | less -S # 美观对齐查看(流式输出)\nxsv headers big.csv # 只看列名\nxsv slice -i 0 -l 20 big.csv # 取前 20 行\nxsv select name,age big.csv | head # 选列+快速预览\nxsv stats big.csv # 各列统计(数值/非数值/缺失等)\n\n过滤:\nxsv search Kyson big.csv\n\n→ 查找任意列中包含 “Kyson” 的行。\n只在特定列中匹配:\nxsv search -s name Kyson big.csv\nxsv search -i -s city tokyo big.csv # 大小写不敏感\n\n正则匹配:\nxsv search -s email '.*@gmail\\.com' big.csv\n\n管道:\nxsv search -s process_node_descp '问题识别' 1761016417085.csv | xsv table | less -S\n\n","description":""},{"title":"使用komari的延迟数据 + grafana自定义延迟看板","url":"https://qixin.ch/posts/grafana/","body":"1. 安装grafana\n1.1 安装依赖\nsudo apt-get update\nsudo apt-get install -y apt-transport-https software-properties-common wget gnupg\n\n1.2 添加 Grafana 官方 GPG key\nwget -q -O - https://packages.grafana.com/gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/grafana.gpg\n\n1.3 添加 Grafana APT 源\necho "deb [signed-by=/usr/share/keyrings/grafana.gpg] https://packages.grafana.com/oss/deb stable main" \\\n | sudo tee /etc/apt/sources.list.d/grafana.list\n\n1.4 安装 Grafana\nsudo apt-get update\nsudo apt-get install -y grafana\n\n1.5 启动 Grafana\nsudo systemctl daemon-reload\nsudo systemctl enable grafana-server\nsudo systemctl start grafana-server\n\n1.6 确认 Grafana 状态\nsystemctl status grafana-server\n\n2. 处理数据\n2.1 安装sqlite3\nsudo apt install sqlite3\n\n2.2 进入komari数据库\nsqlite3 /opt/komari/data/komari.db\n\n2.3 创建视图\nCREATE VIEW v_ping_stats AS\nSELECT\n pr.time AS time,\n pr.value AS value,\n c.uuid AS client_uuid,\n c.name AS client_name,\n t.id AS task_id,\n t.name AS task_name,\n t.target AS target\nFROM ping_records pr\nJOIN clients c ON pr.client = c.uuid\nJOIN ping_tasks t ON pr.task_id = t.id;\n\n3. 创建图表\n3.1 安装Grafana插件\ngrafana-cli plugins install frser-sqlite-datasource\nsystemctl restart grafana-server\n\n3.2 登录Grafana后台\nhttp://服务器IP:3000 账号密码默认都是admin\n3.3 创建dashboard,选择sqlite数据库,填上地址/opt/komari/data/komari.db\n3.4 显示延迟的sql\n\n查看某台vps的延迟\n\nSELECT\n (strftime('%s', time)) AS time, -- 转换为毫秒,\n value,\n task_name\nFROM v_ping_stats\nWHERE client_name = 'xx' -- komari后台设置的vps名称\nORDER BY time;\n\n\n查看某台vps的丢包率\n丢包率的算法不唯一,下面是按照5分钟聚合,结果还受到你上报的频率影响\n\nSELECT\n (strftime('%s', time) / 300) * 300 AS time, -- 按5分钟对齐\n task_name,\n SUM(CASE WHEN value = -1 THEN 1 ELSE 0 END) * 100.0 / COUNT(*) AS loss_rate -- komari中延迟-1代表丢包\nFROM v_ping_stats\nWHERE client_name = 'xx' -- komari后台设置的vps名称\nGROUP BY \n strftime('%s', time) / 300,\n task_name\nORDER BY time;\n\n4. 开放给游客访问\n4.1 修改/etc/grafana/grafana.ini文件\n[auth.anonymous]\n# 启用匿名访问\nenabled = true\n\n# 指定匿名用户的组织(通常是 1)\norg_name = Main Org.\n\n# 指定匿名用户的角色 (Viewer, Editor, Admin)\norg_role = Viewer\n\n# 可选: 隐藏版本信息\nhide_version = false\n\n4.2 重启 Grafana\nsudo systemctl restart grafana-server\n\nGrafana配置相对灵活,大家可以高度自定义\n最后放一下草稿\nhttps://grafana.qixin.ch\n","description":"使用高度自由定制的grafana看板搭建属于自己的延迟看板"},{"title":"一个支持格式化残缺json的工具","url":"https://qixin.ch/posts/json/","body":"用ai结合vscode原生的格式化能力搭建了一个json格式化工具\njson tool\ngithub\n示例:\ninput1\n{"xxa":{"ak":"a","sk":"a"},"xxb":{"ak":"a","sk":"a"},"xxc":{"ak":"a","sk":"a"},"xxd":{"ak":"a","sk":"a"\n\noutput1\n{\n "xxa": {\n "ak": "a",\n "sk": "a"\n },\n "xxb": {\n "ak": "a",\n "sk": "a"\n },\n "xxc": {\n "ak": "a",\n "sk": "a"\n },\n "xxd": {\n "ak": "a",\n "sk": "a"\n\ninput2\nInfo 2025-12-02 14:05:30.949 sxx logid request body ={"bizId":"xx","curMessage":{"messageId":null,"content":"xx","type":"TEXT","role":"USER","shortCutToolId":null,"userCurTime":null,"toolCalls":null},"type":"CHAT","userId":"xx","chatHistory":[{"messageId":"xx","content":"xx","type\n\noutput2\nInfo 2025-12-02 14: 05: 30.949 sxx logid request body ={\n "bizId": "xx",\n "curMessage": {\n "messageId": null,\n "content": "xx",\n "type": "TEXT",\n "role": "USER",\n "shortCutToolId": null,\n "userCurTime": null,\n "toolCalls": null\n },\n "type": "CHAT",\n "userId": "xx",\n "chatHistory": [\n {\n "messageId": "xx",\n "content": "xx","type\n\n","description":"平常工作中,经常使用json格式化,例如格式化日志,但打印日志时为了减少损耗,会对打印json进行截断,截断后网上的json格式工具就失效了提示json异常,但平常使用vscode时就可以对残缺的json以及log中间包含的json进行格式化。"},{"title":"将夸克网盘挂载到vps搭建图片墙","url":"https://qixin.ch/posts/webdav/","body":"使用开源工具挂载夸克网盘的WebDAV服务\n\n\n下载工具\nwget https://github.com/chenqimiao/quarkdrive-webdav/releases/download/v1.3.3/quarkdrive-webdav-x86_64-unknown-linux-gnu.tar.gz\ntar -zxvf quarkdrive-webdav-x86_64-unknown-linux-gnu.tar.gz\n\n\n\n运行工具\nquarkdrive-webdav --quark-cookie '你的cookie' -U '用户名' -W '密码' -p 8080\n\ncookie可以在夸克网页登录后通过控制台获取\n\n\n设置开机启动\ncat <<EOF > /etc/systemd/system/quark.service\n[Unit]\nDescription=Quark Service\nAfter=network.target\n\n[Service]\nType=simple\nExecStart=/root/quark/start-quark.sh\nRestart=always\nUser=root\n\n[Install]\nWantedBy=multi-user.target\nEOF\nsystemctl daemon-reload\nsystemctl enable quark\n\n\n#!/bin/bash\n/root/quark/quarkdrive-webdav --quark-cookie "$(cat /root/quark/cookie.txt)" -U admin -W password -p 8082\n\ncookie比较长,可以放在/root/quark/cookie.txt中\n\n\n将WebDAV挂载到vps\n\n\n安装工具\napt install davfs2\n\n\n\n创建挂载目录\nmkdir /path/webdav\n\n\n\n挂载 WebDAV\nmount -t davfs https://webdav.drive.com/dav /path/webdav\n\n\n\n输入账号密码\n使用以上挂载命令后就会让输入账号密码,填入第一步设置的账号密码\n\n\n配置开机启动\nvi /etc/davfs2/davfs2.conf\n\n修改打开use_locks参数,将value从原来的1,改为0\n5.1 修改davfs2的secrets文件,添加认证信息\n将webdav的地址以及用户名密码输入到最底部。\ncat <<EOF >> /etc/davfs2/secrets\nhttps://webdav.drive.com/dav 用户名 密码\nEOF\n\n5.2 配置systemd文件\n⚠️注意:通常情况下,挂载单元文件(mount unit)的命名是按照要挂载的路径来命名的。这种命名约定是由systemd规定的,以便于自动识别和处理挂载点。如挂载点 /mnt/data 的挂载单元文件应命名为 mnt-data.mount\ncat <<EOF >> /etc/systemd/system/path-webdav.mount\n[Unit]\nDescription=Mount WebDAV Share\nAfter=network-online.target\nWants=network-online.target\n\n[Mount]\nWhat=https://webdav.drive.com/dav #修改为自己的webdav地址\nWhere=/path/webdav #修改为自己的挂载路径\nType=davfs \nOptions=_netdev,users,rw\n\n[Install]\nWantedBy=multi-user.target\nEOF\n\n保存后重新加载systemd配置并启动\nsystemctl daemon-reload\nsystemctl enable path-webdav.mount\n\n最后可以使用df -h查看一下是否生效\n\n\n将挂载数据同步到本地\n由于webdav速度太慢,严重影响网页加载速度,因此可以将挂载数据同步到本地。\n\n\n安装rclone\n# 示例:Debian/Ubuntu\nsudo apt update\nsudo apt install rclone\n\n# 示例:CentOS/RHEL\nsudo dnf install rclone\n\n\n\n使用 rclone sync 进行定时同步\n2.1 基本的同步命令\nrclone sync /var/www/quark/pictures /var/www/pictures --ignore-times --delete-during\n\n2.2 设置定时任务\n打开 crontab 配置\ncrontab -e\n\n在文件末尾添加一行,例如设置为每 5 分钟 同步一次(将 /path/to/rclone 替换为实际的 rclone 路径,通常是 /usr/bin/rclone):\n*/5 * * * * /usr/bin/rclone sync /var/www/quark/pictures /var/www/pictures --ignore-times --delete-during --log-file=/var/log/rclone_sync.log\n\n\n\n使用files.gallery搭建图片墙\n可以使用破解版本Smooth-Files-Gallery\n\n\n将下载的index.php文件上传到vps的/var/www/Photos目录下\n\n\n配置caddy(也可以使用nginx)\ncat <<EOF > /etc/caddy/photo.xx.xx.service #自行修改\nphoto.xx.xx { ##自行修改\n # 设置网站根目录\n root * /var/www/Photos\n\n # 开启 gzip 压缩,加快图片加载\n encode gzip\n\n # 处理 PHP 文件 (关键步骤)\n # 注意:unix 路径可能因系统不同而不同,下面是常见的 Ubuntu/Debian 路径\n # 如果找不到该文件,请查看下文的“检查 PHP”部分\n php_fastcgi unix//run/php/php8.2-fpm.sock\n\n # 静态文件服务(用于直接展示图片)\n file_server\n request_body {\n max_size 200MB\n }\n}\nEOF\n\n重启caddy\nsystemctl restart caddy\n\n\n配置文件权限\n\nchmod -R 777 /var/www/Photos\n\n\n配置Files.Gallery\n4.1 先放问一下http://photo.xx.xx,在index.php所在的文件夹下会生成_files,里面有个config.php, 将里面的root目录改为/var/www/pictures\n\n\n\n设置上传文件的大小\n5.1 caddy上面已经配置了200M\n5.2 PHP 上传大小限制(必须设置,否则 Caddy 放开也没用)\n\n/etc/php/8.2/fpm/php.ini\n/etc/php/8.2/cli/php.ini\n\n修改:\nupload_max_filesize = 200M\npost_max_size = 200M\nmax_file_uploads = 100\n\n重启PHP-FPM:\nsystemctl restart php8.2-fpm\n\n验证生效\nphp -i | grep upload_max_filesize\nphp -i | grep post_max_size\n\n\n\n备注\n解释一下上面各个文件的作用\n路径作用\n/var/www/Photos/index.phpFiles.Gallery 的入口文件,用于展示图片墙。因 files.gallery 会在该目录下创建 _files 等文件,需赋予写权限。\n/var/www/Photos/_files/config.phpFiles.Gallery 的配置文件,用于设置图片墙参数,如根目录、缓存时间等。\n/var/www/quark/pictures挂载的 WebDAV 目录,用于存储图片。\n/var/www/pictures从挂载点同步到本地的目录,Files.Gallery 从此处读取图片。因文件会被覆盖,index.php 需放在其他文件夹。\n/var/log/rclone_sync.logrclone 同步日志文件,记录同步过程中的信息。\n/etc/caddy/photo.xx.xx.serviceCaddy 配置文件,用于配置图片墙域名、根目录、上传文件大小等。\n\n引用\n\nLinux使用davfs2挂载webdav作为本地磁盘并实现自动挂载\n\n","description":"使用夸克网盘的webdav服务可以将百度夸克网盘挂载到本地电脑上,就像操作本地电脑硬盘一样操作网盘,非常方便。"},{"title":"VPS运营商以及线路介绍","url":"https://qixin.ch/posts/as/","body":"声明: 高贵的 IPLC 不在此种范围之内,99% 的个人用户买不起 IPLC 线路的 VPS,所以不在文内进行讲解。\n国内几大骨干网介绍\n目前国内有三大运营商:电信、联通、移动。\n运营商骨干网名称自治系统编号(AS号)\n中国电信163 (CHINANET)AS4134\nCN2 (CNCN)AS4809\n中国联通169 (China Unicom BackBone)AS4837\nA网 (Industrial Internet Backbone)AS9929\n中国移动CMNET (境内骨干网)AS9808\nCMI (境外骨干网)AS58453\n\n科研教育用途小型骨干网:\n\nCERNET (教育网,主用于高校): AS4538\nCSTNET (科技网): AS7497\n\n\n注意:\n\n如果您国内用的是手机运营商或普通家用宽带,对应 AS 号是:电信 AS4134,联通 AS4837,移动 AS9808。\n移动是个怪胎,普通线路不能直接连接海外,必须用 AS58453 (CMI) 才行。\n\n\n\n骨干网详情介绍\nAS4134 CHINANET 中国电信163骨干网\n\n宽带业务范围: 普通家用宽带、商用宽带、政企宽带\n海外加速专有业务: 163精品网套餐(上海地区)\n已知出口: 北京、上海、广州\n特点: 全国规模最大的骨干网,享有最大的国际出口。一般性电信宽带或商宽访问境外网站,如果对方 ISP 没有购买电信的 CN2 Transit,则走此骨干网。\n\nAS4809 CNCN(CN2) 中国电信第二代骨干网\n\n宽带业务范围: 家用游戏及海外加速宽带、商用跨国优化宽带、政企宽带\n海外加速专有业务: CN2国际精品网套餐(覆盖几乎全国)\n已知出口: 北京、上海、广州、乌鲁木齐\n重点:CN2 分类\n\nCN2 GIA: 归属电信,拥有独立的回国线路,目前负载较轻。\nCN2 GT: CN2 产品线中的 Global Transit 产品,拥有国际线路,但没有回国路线。\n\n\n特点: 技术先进,灵活性高,一般对海外聊天、游戏有较高需求的会使用。目前是国内到国际网络高峰期能提供最好速率和体验的骨干网之一。\n\nAS4837 China Unicom BackBone 中国联通骨干网\n\n宽带业务范围: 家宽、商宽、政企宽带\n已知出口: 北京、上海、广州\n特点: 除非访问的对方 ISP 购买了电信 CN2 Transit/联通的 CU Premiun,否则一律走 169 骨干网。出国拥堵程度小于电信 163,但总体速度和延时可靠性不如 CN2。因价格便宜,是游戏爱好者(国际服玩家)及普通外教课程需求者的首选宽带之一。\n\nAS9929 CHINA UNICOM Industrial Internet Backbone 中国联通工业互联骨干网\n\n宽带业务范围: 商业宽带、政企宽带\n海外加速服务: 本网专做海外加速服务\n已知出口: 北京、上海、广州\n特点: 前身为网通骨干网,后改为联通 A 网,用于国际互联加速服务。价格昂贵,主要为跨国企业使用,已无家宽业务。\n\nAS9808 China Mobile 中国移动骨干网\n\n宽带业务范围: 家宽、商宽、政企宽带\n已知出口: 北京、上海、广州\n特点: AS9808 为移动境内骨干网,所有出境流量通过 AS58453 (CMI) 与外网互联。\n\nAS58453 CMI 中国移动国际骨干网\n\n特点: 移动的国际段骨干网,现已不再具有国际出口优势,目前三网中只略好于电信 163。\n\nAS4538 CERNET 中国教育研究网络\n\n宽带业务范围: 各大高校的校园网和部分大型国内云服务提供商\n已知出口: 北京清华大学\n特点: 不服务于家宽、商宽、政企。网传效果不如 CN2。\n\n\n总结(骨干网):\nCN2 GIA 是理论上可以包容所有网络环境,提供稳定且长期服务搭建节点或建站的不二之选,但价格是普通 VPS 的 10 倍以上。\n\n国内ISP与国际ISP的互联详情\n📍 中国香港\n常见运营商境内可直连骨干网连接质量说明\nCMI (AS58453)全网(高性价比)移动自己的国际骨干网,境内连接质量非常高,只要对方接入足够 Transit,三网访问优先级高。\nCUG (AS10099)全网(联通优先)联通自己的国际骨干网,同 CMI,联通用户访问优先级最高。\nNTTAS4809 (CN2)、AS58453 (CMI)CN2 到 NTT 有时不可靠,延时抖动剧烈。移动高峰期直连可能被 QoS,速度不佳。\nPCCW/HKTAS4134、AS4809、AS4837、AS9929、AS58453综合连接效果一般。联通 A 网 (AS9929) 连接质量最好。移动 CMI 路由不稳定,不推荐。\nTelstra GlobalAS4134、AS4837、AS4538、AS9929、AS58453三网都可直连,非常友好。电信 163 在香港地区直连 Telstra 效果顶级,推荐。移动 CMI 互联带宽较小,高峰延时可能猛涨。\nCHTAS4134、AS4837、AS58453电信 163 效果极差,不推荐。联通 169 表现较好。移动 CMI 高峰表现极度拉垮。\nHKBN/WTTAS4134、AS4837、AS58453三网直连,主要用于流媒体解锁。无特殊优势。\nHEAS58453 (经 HKIX)、AS9929 (via HKIX)电信、联通 169 和教育网都会绕美。\nTaTaAS4837、AS9929联通直连,大部分情况下回程绕美。爆炸绕路三幻神之首。\nCogentco无爆炸绕路三幻神之一。电信、联通 9929、移动和教育网绕美,联通 169 绕新加坡。\nGTT无三网均会绕美。\n\n\n香港 VPS 总结:\n\n黄金搭档:移动直连 + 电信直连。\n青睐香港的原因:奈飞港区字幕/配音优化、软件 APP 简体中文优化、翻墙节点集中。\n\n\n\n📍 中国澳门\n常见运营商境内可直连骨干网连接质量说明\n中国电信(澳门)AS4134、AS4809 (GIA)国内全部网络都可直连。\nCTMAS4134、AS4837、AS58453并非所有 IP 都直连。机房托管业务分国内优化和国际路由,平民 VPS 多为国际路由。移动需先经香港 PoP,延时略高。\nMTelAS4134、AS58453与电信 163 互联容量小,互联效果不佳,高峰延时波动大。联通绕日本 NTT。\n\n\n📍 中国台湾\n常见运营商境内可直连骨干网连接质量说明\nHiNetAS4134、AS58453、AS4837台湾最大宽带提供商。电信和联通延迟比移动高。电信 163 效果差,联通 169 表现较好。移动 CMI 高峰极度拉垮。\nTFN/SeedNet/TaNet/HomePlus不详运营商较少,对大陆优化相对可以。但台湾节点流媒体解锁不如香港友好。\n\n\n📍 日本\n常见运营商境内可直连骨干网连接质量说明\nNTTAS4134、AS4809、AS4837、AS9929、AS58423AS9929:目前国内直连延时低且稳定,速度取决于 9929 带宽。电信 163:日常大爆炸,质量最差,高峰丢包率惊人。移动目前仍绕香港 CMI。\nIIJAS4134、AS4837、AS58423电信 163 互联质量远好于 NTT。联通 169 综合好于 163。移动已通过东京 PoP 直连。是日本地区对中国友好、价格实惠的 ISP。\nBBTEC (软银)AS4134、AS4837、AS9929、AS58423联通 169 仍是到日本最好的线路之一。联通 9929 延时稳定,速度取决于 9929 带宽。电信 163 延时较低但速度不佳。北方移动不友好。\nKDDIAS9929价格昂贵,低负载,延迟一般。\n\n\n日本 VPS 总结:\n\n日本 VPS 较贵,但优化友好,流媒体解锁(日区看番)是一个优势。\n\n\n\n📍 新加坡\n常见运营商境内可直连骨干网连接质量说明\nNTTAS4134、AS58453电信 163:互联带宽很小,几乎全天塞满,延时异常高,丢包率极大,非常不推荐。移动 CMI 互联带宽大,是移动用户访问主流渠道。联通 169/9929 不能直连。\nSingTel (新加坡电信)AS4837、AS9929、AS58453联通 169 表现稳定,是唯一双向新加坡直连的国内 ISP。移动 CMI 高峰延时和丢包显著增长。电信 163 绕美西 Tata/Telia,速度非常糟糕。\nTelstra Global香港直连的骨干网速度与香港 Telstra 差不多。\nStarHubAS4134、AS4837、AS58453实际路由表现一般。电信 163 去程直连回程绕路,联通 169 回程直连去程绕日 NTT。移动较好。\nMyRepublic无无国内御三家互联,最好使用移动 CMI 或 CN2 中转。\nCogentcoAS4837联通 169 在新加坡开通新 Peer,延时成绩优秀。\nTataAS4387、AS9929 (从 AS10099 接入)联通直连,可经由 AS4837 直连广州入口。\n\n\n📍 韩国\n常见运营商境内可直连骨干网连接质量说明\nKT (Korea Telecom)AS4134、AS4809、AS4837、AS9929、AS58453电信 163/CN2 走上海出口。联通 9929 延迟极低,高峰几乎无丢包,但经常抖动。\nSK TelecomAS4134、AS4809、AS4837、AS58453SK-CN2 非常稳定,基本无丢包但看起来绕港。CMI 与 SK Boardband 在香港 Peer。\nLG (Uplus)AS4134、AS4809、AS4837、AS9929联通 169 (上海) 配合单边加速高峰期速度不错,但 ICMP 丢包率特别高。联通 9929 延迟低但速度不稳定。\n\n\n📍 欧洲/北美地区\n🌍 欧洲德国\n常见运营商境内可直连骨干网连接质量说明\nDTAG (德国电信)AS4134、AS4837、AS9929延迟 200ms+。电信 163 普通家宽会被强制丢包。联通 169 南方绕美。AS9929 稳定,延迟优于 163/169,速度勉强。\nCogent CommunicationsAS4134、AS4837、AS9929、AS58453联通 9929 互联主力。速度玄学,单线程慢,多线程能跑满。\n\n🇺🇸 美国洛杉矶&圣何塞\n常见运营商境内可直连骨干网连接质量说明\nHE (Hurricane Electric)AS4134、AS4837、AS58453电信 163 互联速度限制严重。联通 169 互联性价比高。CMI 与 HE 互联质量差。\nGTTAS4134、AS4837、AS58453联通 169 较大地依赖 GTT,延时高,速度不乐观。电信 163 互联质量出乎意料的好,全天几乎不丢包。\nTelia (Arelion)AS4134、AS4809、AS4837、AS58453中规中矩的线路。\nCogent CommunicationsAS4134、AS4837、AS9929、AS58453电信 163 较大程度依赖 Cogentco 互联,天天爆炸。\nVerizonAS9929延迟不是最优,单线程速度不是最优。多线程速度能跑满,非常玄学。\n\n","description":"购买vps时需要注意,不同的vps运营商提供的网络线路不同,影响到vps的访问速度和稳定性。也是解决价格的决定性因素。"},{"title":"同一个模型部署在不同显卡上,结果可能不同","url":"https://qixin.ch/posts/model/","body":"以下是gpt的答复\n非常好的问题,这种情况在实践中确实可能发生,即使模型文件、参数、代码和输入完全相同。\n你看到“相同模型 + 不同显卡 + 相同请求参数 → 输出不同”这一现象,通常是由底层数值计算差异引起的。下面是详细原因分析👇\n\n🧩 一、主要原因:浮点数计算的非确定性\n\n\n不同 GPU 架构的浮点计算实现不同\n\n不同显卡(如 NVIDIA A100 vs RTX 4090)虽然都支持 FP16/FP32/FP64,但在指令级实现(如 FMA 融合乘加、舍入模式、累积顺序)上可能略有不同。\n这些微小的差异会在神经网络的数亿次运算中被放大,导致最终结果略有偏差。\n\n\n\n并行计算顺序不一致\n\nGPU 上很多操作(如 sum、matmul、softmax)是多线程并行的。\n浮点加法不满足结合律:\n\n(a + b) + c ≠ a + (b + c)\n\n所以线程调度或 kernel 执行顺序不同,也可能造成输出不同。\n\n\ncuDNN/cuBLAS 算法的非确定性\n\nNVIDIA 的深度学习库(cuDNN、cuBLAS)在同一个操作上可能有多个实现版本,驱动或硬件不同会自动选择不同 kernel。\n某些算法(如卷积的 FFT 实现、winograd)并不是确定性的。\n\n\n\n\n🧠 二、如果模型涉及随机性,差异更明显\n如果模型使用了:\n\ndropout\n随机初始化(未固定种子)\n随机采样(如 temperature > 0 的生成模型)\n\n那么即使同一张显卡多次运行,输出也会不同,更别提不同 GPU。\n\n🛠 三、如何尽可能让结果一致\n\n\n启用确定性模式\nimport torch\ntorch.use_deterministic_algorithms(True)\n\n或者\ntorch.backends.cudnn.deterministic = True\ntorch.backends.cudnn.benchmark = False\n\n\n\n固定随机种子\nimport random, numpy as np, torch\nrandom.seed(42)\nnp.random.seed(42)\ntorch.manual_seed(42)\ntorch.cuda.manual_seed_all(42)\n\n\n\n使用相同 CUDA/cuDNN/cuBLAS 版本\n不同驱动版本选择的算法路径可能不同,要尽量统一:\nnvidia-smi\nnvcc --version\npython -m torch.utils.collect_env\n\n\n\n关闭混合精度或 FP16 模式\nFP16 的舍入误差更明显。若需要高一致性,可以统一为 FP32 计算。\n\n\n锁定库和框架版本\n确保 torch、transformers、xformers、triton、onnxruntime 等版本完全一致。\n\n\n\n📊 四、现实中的例子\n即使是 OpenAI、Meta、Google 的内部推理集群,也会记录到“不同显卡输出略有不同”的问题。例如:\n模型硬件差异表现\nLlama 2 70BA100 vs H100logit 第三位小数差异\nWhisper-large3090 vs A10输出 token 顺序偶尔偏移\nStable Diffusion3060 vs 4090图像色调略有差异\n\n\n✅ 总结一句话\n\n“相同模型 + 不同显卡 → 不同输出”并不是异常,而是浮点计算和并行算法的非确定性本质导致的。\n\n如果你能告诉我:\n\n使用的框架(如 PyTorch、TensorFlow、ONNX Runtime 等);\n显卡型号;\n是否开启了 FP16 或混合精度;\n\n","description":"最近工作中遇到同一个模型服务被自动缩容后,迁移到一个更好的显卡上后,发现相同测试集产出的结果不一致,经过测试才发现模型文件部署在不同显卡上的结果不同。"},{"title":"Snell 一键脚本开启多个端口监听","url":"https://qixin.ch/posts/snell/","body":"主要使用的systemctl service的变量功能,将端口当成变量传给service,每个端口启动一个service\n将内容保存到snell.sh中,使用下面命令赋予执行权限\nchmod +x snell.sh\n\n./snell install #安装官方snell-service\n./snell create 1234 #新增端口\n./snell list #查看目前端口列表\n\n脚本内容:\n#!/usr/bin/env bash\nset -e\nsnell_server="/etc/systemd/system/snell-server@.service"\nsnell_bin="/usr/local/bin/snell-server"\nsnell_dir="/etc/snell"\n\ncheck_root() {\n [[ $EUID -ne 0 ]] && echo "请使用 root 运行" && exit 1\n}\n\ninstall_binary() {\n mkdir -p "$snell_dir"\n arch=$(uname -m)\n [[ "$arch" == "x86_64" ]] && arch="amd64"\n ver="5.0.0"\n url="https://dl.nssurge.com/snell/snell-server-v${ver}-linux-${arch}.zip"\n wget -qO snell.zip "$url"\n unzip -o snell.zip && mv snell-server "$snell_bin"\n chmod +x "$snell_bin"\n rm -f snell.zip\n cat >"$snell_server" <<EOF\n[Unit]\nDescription=Snell Service\nAfter=network-online.target\nWants=network-online.target systemd-networkd-wait-online.service\n[Service]\nLimitNOFILE=32767 \nType=simple\nUser=root\nRestart=on-failure\nRestartSec=5s\nExecStartPre=/bin/sh -c ulimit -n 51200\nExecStart=${snell_bin} -c ${snell_dir}/config-%i.conf\n[Install]\nWantedBy=multi-user.target\nEOF\n}\n\ncreate_config() {\n port=$1\n [[ -z "$port" ]] && echo "用法: $0 create <port>" && exit 1\n conf="$snell_dir/config-$port.conf"\n [[ -f "$conf" ]] && echo "配置已存在: $conf" && exit 1\n read -p "PSK(留空随机): " psk\n [[ -z "$psk" ]] && psk=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 16)\n cat >"$conf" <<EOF\n[snell-server]\nlisten = 0.0.0.0:${port}\npsk = ${psk}\nobfs = off\nipv6 = false\ntfo = true\ndns = 1.1.1.1,8.8.8.8\nversion = 5\nEOF\n echo "已创建 $conf"\n}\n\nstart_instance() {\n port=$1\n systemctl enable --now snell-server@"$port"\n}\n\nstop_instance() {\n port=$1\n systemctl stop snell-server@"$port"\n}\n\nlist_instances() {\n systemctl list-units --type=service | grep snell-server@\n}\n\ncase "$1" in\n install) install_binary ;;\n create) create_config "$2"\n start_instance "$2" ;;\n stop) stop_instance "$2" ;;\n list) list_instances ;;\n *) echo "用法: $0 {install|create <port>|stop <port>|list}" ;;\nesac\n\n","description":"之前用的snell一键脚本只能创建一个端口,只能和朋友用一个端口不方便。今天用AI糊了个脚本可以开启多个端口监听。"},{"title":"Arthas 使用记录","url":"https://qixin.ch/posts/arthas/","body":"Arthas 官网\n1、进入 webShell 下载 arthas\ncurl -O https://arthas.aliyun.com/arthas-boot.jar\n\n2. 启动 arthas\n方法一\nwebShell# java -jar arthas-boot.jar\n[INFO] arthas-boot version: 3.5.5\n[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.\n* [1]: 364 web-app-1.21.4.jar\n1 //输入上面的 jar前面的序号\n\n方法二\n#找到java进程的pid\nwebShell# ps -ef|grep java\nwebShell# java -jar arthas-boot.jar 364 # pid\n\n3. 常用命令\nwatch com.xx.sdk.entity.EntityMetaUtils getEntitySchema "{params[0],throwExp}" -e -x 2\n\nwatch com.xx.application.service.FieldPageQueryService fillQuoteEntityFieldInfo "{params[1]}" -x 2\n\nwatch com.xx.runtime.container.factory.MarketContainerFactory loadDevComponentContainer "{returnObj.devSubscribeMap}" -x 2\n\nwatch com.xx.domain.versions.DevVersionQueryService getFromCache "{params, returnObj}" -x 2 '#cost>30'\n\nwatch com.xx.meta.execute.sdk.pipeline.PipelineService queryActivePipelineName "{params, returnObj}" -x 5\n\nwatch com.xxtask.dataimport.FieldService fieldTransform "{params,returnObj}" 'params[3].fieldName == "address__city"' -x 5\n\ntrace com.xx.util.mybatis.MetaDataAbstractReader loadOverrideData\n\nwatch com.xx.domain.bizsys.data.entity.DomainEntityMeta getFieldMetaList 'returnObj' -x 3 'returnObj[0].entityName == "Mar"'\nwatch com.xx.thrift.service.converter.EntityDetailConverter buildTemplateInfo "{params, returnObj}" -x 5 'params[1].name=="ppe_tongji01__c"'\n\nwatch com.xx.infrastructure.converter.entity.EntityFieldConverter convertInner 'params' 'params[1].entityName == "MarketingCampaignMember"'\n\ntrace com.xx.util.mybatis.MetaDataOverrideUtil loadOverrideData 'params[1][1].name == "validator_len__object_account__primaryName"'\n\nclassloader -t\n\nognl -c 6ad5c04e '#obj=new com.xx.common.i18n.I18nString("xxx.meta.button.show_name.create","xx"),@com.xx.common.i18n.I18nTranslateService@translate(@com.xx.common.enums.LanguageEnum@en, #obj)' -X 1\nognl -c 6ad5c04e '#obj=new com.xx.util.QueryContext("kyson_CN","","xxx",11111111,"",null,null), @com.xx.runtime.container.DataContainerFactory@loadTenantEntity(#obj)' -x 1\n\n#obj=new com.xx.util.QueryContext("kyson_CN","","xxx",11111111,"",null,null)\nognl -c 6ad5c04e '#obj=@com.xx.util.QueryContext@newBuilder()@withTenantCode("kyson_CN")@build()'\n\nognl -c 6ad5c04e '#obj=@com.xx.util.QueryContext@newInst("xxx")'\n\nognl -c 6ad5c04e '#obj=@com.xx.util.QueryContext@newBuilder().withTenantCode("kyson_CN").withSys("xxx").withEmployeeId(11111111L)'\n\nognl -c 6ad5c04e '#obj=@com.xx.util.QueryContext@newBuilder().withTenantCode("kyson_CN").withSys("xxx").withEmployeeId(11111111L).build(), @com.xx.runtime.container.impl.DataContainerFactory@refreshPageRoute(#obj).suiteNamePageMap.get("1616140138847_eskqfthy")'\n\nognl -c 1be6f5c3 '#obj=com.xx.infrastructure.mapper.BizSelfMapper'\nognl -c 1be6f5c3 '#obj=@com.xx.util.SpringUtils@getBean("bizSelfMapper").getCurrentTimestamp()' -X 1\n\n\n\n","description":"Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱。"},{"title":"《蛤蟆先生去看心理医生》读书笔记","url":"https://qixin.ch/posts/hama/","body":"\n阅读使人充实,会谈使人敏捷,写作与笔记使人精确 ——培根\n\n📝 笔记方法:康奈尔笔记法 (Cornell Notes System)\n康奈尔笔记法是由美国康奈尔大学教授沃尔特·波克发明的一种笔记方法。\n\n目的: 将笔记纸分为3个栏目:笔记、关键词、总结,来高效记笔记,并便于复习巩固知识点。\n操作步骤:\n\n  用简洁的语句在笔记栏记下重点知识。\n  将笔记栏中的知识点提炼为关键词和要点,写在关键词栏。在总结栏写下本次学习总结。\n  遮盖笔记栏的内容,通过关键词栏的要点概括,复述出笔记内容来巩固知识。\n\n\n\n📚 导读\n这是一本入门级心理学书籍,旨在帮助患有抑郁的人走出困境。\n蛤蟆本是一个热情、时尚又爱冒险的家伙,惹出过不少麻烦和笑话。但他现在陷入抑郁,不能自拔。他的朋友们(獾、河鼠、鼹鼠)决定督促他重视这个问题,并带他去接受心理咨询。\n\n📌 笔记内容提炼(关键词与要点)\n关键词笔记栏要点\n心理咨询 / 自发做事1. 心理咨询是一个自发的过程,咨询师和来访者双方都得出于自愿。只有为自己而非取悦朋友才想咨询的时候,双方才能真正合作。2. 咨询师相信每个人都有能力变得更好。\n儿童自我状态 / 行为3. 处于**“儿童自我状态”时,行为和感受都像一个孩子**,不同于“幼稚”。4. 自然型儿童的基本情感:快乐和深情、愤怒、悲伤、恐惧。5. 感受和行为与小时候的自己如出一辙,与实际年龄无关。6. 早期的经历塑造了人格的雏形,无法否认或忘记。7. 适应型儿童情感:顺从行为(同意、取悦父母、道歉、依赖父母)。8. 成长的本质是减少并最终打破对父母的依赖,成为一个独立自主的人。9. 撒泼是表达愤怒的幼稚的短暂方式。10. 怄气是表达愤怒的幼稚的长期方式。\n儿童状态的后果11. 成人处在儿童状态时,道德层面上没有“错”,但会导致:被人嘲笑/尴尬,并让人觉得是失败者。12. “共谋”:无意识地配合对方制造不快,是在玩心理游戏,输的人才是赢家。\n学习是痛苦的13. 转变是痛苦的,因为看到自己不一定总是喜欢自己的样子。14. 从当下变成想成为的自己,需要经历行为和态度的转变,付出艰辛的努力、勇气和决心。\n父母自我状态 / 挑剔型父母15. “父母自我状态”:包含从父母那里学到的所有价值观和道德观,以及对生活的评判标准。16. 挑剔型父母:爱批评人、愤怒、严厉。17. 没有一种批判比自我批判更强烈,也没有一个法官比我们自己更严苛。\n成人状态 / 学习知识18. “成人状态”:指用理性而不是情绪化的方式来行事,应对此时此地的现实状况,能计划、考虑、决定、行动。19. 在此状态下,知识和技能能为自己所用,不被过去的声音或童年情绪驱使。20. 三种状态都是必需的,但**“成人状态”有它的特殊重要性**。21. 只有在“成人自我状态”里,才能学到关于自我的新知识。22. 在“儿童状态”时,会再现过去的情绪,但学不到任何新的东西。23. 在“父母状态”时,重复旧的观念和价值观,没有新知识和新理念的空间。24. 进入成人状态难,是因为需要艰辛的努力和刻意的思考。\n自己选择自己的感受25. 没有人能“让”我们产生什么感受,是我们**“选择”了自己的感受**(愤怒或悲伤)。26. 责怪是人处在**“儿童自我状态”**里做的事情。27. “成人自我状态”的人会负起责任。\n自证预言28. “自证预言”:我们会控制事件的发生,从而确保预言会成真,确保自己的世界和预期的一样。\n人生坐标 / 必然后果29. 人生最早期的阶段(出生到大约四五岁)发生的一切对我们影响重大。30. 核心问题:“我是怎么看自己的?我好吗?” 和 “我是怎么看别人的?他们好吗?”。31. “我不好,你好”:“受害者游戏”、“PLOM: poor little old me\"。 32. “我好,你不好”:处于父母自我状态,常玩“Now I've Got You, You Son of Bitch”、“你为什么总让我失望?”。33. “我好;你也好”:选择了这个坐标是许下了终生的承诺,人生坐标是动态的过程。\n情商34. 情商:理解你内心的情感世界,并且还能掌控它。35. 高情商:有强大的自我意识;能管理情绪;能控制冲动,懂得延迟满足。\n\n✨ 总结栏(总结、反思与观点)\n\n每个人都有儿童自我状态、父母自我状态。\n如果不对其他人经常生气,可能就是经常对自己生气(否定自己)。\n在成人状态下才会学习到新的知识,因为在其他两种状态下,我们有例可循(基础情感、父母影响),不需要思考。\n幼时父母的“暴力”,我们要选择原谅,原因有很多(父母是否是故意施暴,父母是否健在…………..)。\n处在父母自我状态下的人不会抑郁。他们觉得自己无敌好,别人无敌差,这样的人没心没肺。\n对一个人从依赖转变成了对抗,说明我们成长了。\n现在大环境下,大家普遍关注、研究物理世界,对于情商世界知之甚少。“不在沉默中爆发,就在沉默中死亡”这也适用于情感世界。\n怎样成为高情商的人:客观看问题,三思而后行。\n\n📊 附图信息(结构概念)\n自我状态结构\n\n儿童如何释放愤怒(由强到弱)\n\n人生坐标(我与你)\n\n","description":"基于《蛤蟆先生去看心理医生》的内容,整理的关键点,涵盖儿童、父母、成人自我状态、人生坐标和情商等核心概念。"},{"title":"厉害的人如何分析问题","url":"https://qixin.ch/posts/analyze/","body":"☆ 我先来举一个栗子 :\n假设,你是一家创业公司的CEO。\n最近,你发现公司的业绩,一路下滑,你打算找业务部主管王小锤聊一下,看看到底发生了什么,下一步该如何应对。\n于是,你把他叫到了办公室,一脸严肃的问到:小锤,最近公司业绩一直在下滑,你打算下一步怎么办?\n小锤有些颤抖,紧张的说到:\n老板,这两个月团队走了几个得力干将。另外,这段时间,市场上出现了一个竞争对手,和我们的产品功能基本一致,但价格比我们低了许多,用户现在都觉得我们的产品太贵,都跑去买他们的了,所以业绩才下滑。\n如果能帮我再招募几个销售,适当的再给我一些折扣的权利,我有信心,业绩一定能提上去!\n你听上去感觉像是借口,便质问到:\n再招几个销售没问题,我帮你去和人力资源部的李总打声招呼。\n可价格高不是理由吧,我们一直都是这个价格在卖,而且我们为了保证产品质量,用的都是好材料,利润本来就不高,现在你再一打折,利润就更少了…\n小锤看你有些犹豫,就继续说到:\n现在市场发生变化了,竞争对手开始主动降价,我们也要跟进,晚了也许市场就没了!\n通过薄利多销,先把竞争对手赶出去,把市场拿回来!\n被他这么一说,你心头一紧,感觉挺有道理,频频点头,还没等你开口,小锤又接着说:\n只要您给我打折的权利,再给我配2个人,我保证下个月的业绩能有2倍的提升!把市场给拿回来!做不到我就走人!\n你被王小崔诚意所打动,脸上露出了迷人的微笑,便许诺了他提出的条件...\n一个月过去了…\n公司的销售额确实提升了2倍,但是由于都是打折出售,算上新增的人力成本,团队的运营成本,利润竟然变为了负数!\n并且,竞争对手竟然又降价了,摆出了一副誓死要打价格战的架势,小锤又向你提出了需要更高折扣的请求...\n怎么办?\n再降?就会亏更多!\n不降?市场就没了...\n裁人?团队就散了。\n小锤,你这是在坑我啊...\n你焦头烂额...\n为什么会这样?\n那是因为你只看到了「表面问题」并没有找到「本质问题」,吃错了药!\n什么是表面问题,什么是本质问题?我们又应该如何找到本质问题呢?\n☆ 问题的本质\n要找到本质问题,我们得先看一下到底什么是「问题」?它是如何产生的?\n比如我问你:什么是区块链?\n如果你不知道区块链的含义,那么它对你来说是个问题;而如果你的认知中,已经拥有了区块链的认知,那么这对你来说就不是个问题,或者说,你已经解决了这个问题。\n\n再比如,我问你:你为什么这个月业绩那么差?\n这是一个问题吗?\n这就不一定了…\n如果说,公司给你的业绩目标是100万,你做了50万,那么这就是个问题。\n\n但是,如果目标是100万,你也做了100万,那么这就不是个问题。你听到后会反问我:我哪里差了?!\n\n所以「问题」是什么?\n「问题」就是:期望与现状的落差部分\n假设某件事的期望值是(B),现状是(B’),那么(B'→ B)这个落差部分,就是问题。\n\n为什么我们常说:没有问题,就是最大的问题?\n因为没有问题,就意味着你不知道目标在哪里,也不知道现状是什么,自然就不知道有什么问题,只是当一天和尚撞一天钟,随波逐流,一脸迷茫...\n比如你刚对一群人讲完一大段话,然后问:大家还有没有问题?\n大家回答你:没有问题…\n你千万别天真的以为大家都听懂了,更大的可能是:\n他不知道什么算真正的听懂了,以及为什么要听你说这一大段,他没有一个期望值(B);\n也不知道自己听懂了什么,没听懂什么,处在游离状态,找不到自己的现状(B’)…\n因此,不是他完全听懂了,没有问题,而是不知道自己有没有听懂,不知道什么算完全听懂,因而找不到这个「落差」在哪里,没有发现落差也就没有发现问题,所以只能回答:没有问题...\n我们所有的解决办法,都应该是围绕(B'→ B)的这个部分来展开思考的,找不到这个落差部分,我们的解决方案也就无从开始。\n可是,我们日常工作、生活中的交流并不是这样的...\n往往在还没弄清楚问题是什么的情况下,就急于开始给出自己的建议…\n比如,文章开头的问题:“小锤,最近公司业绩一直在下滑,你下一步打算怎么办?”\n这个问题,其实就很模糊,怎么算下滑?目标业绩是多少?现在业绩是多少?下滑的比例是多少?过去几个月具体是什么情况?\n是原来做100万,现在变成30万?还是原来做100万,现在下降到80万?\n虽然都是业绩变差了,但这两个问题,显然是不同的问题,一个是要解决70万差额的断崖式下跌,一个是要解决20万差额的业绩波动,你给的解决方案当然应该不同。\n如果是第一个问题,那可能就需要动大手术了,比如降价拉销售、整个团队大换血,甚至是战略调整;\n而如果是第二个问题,那么补两个销售,再给团队打一针鸡血,老大一声吼,大伙们向前冲,也许就能解决…\n又比如,闺蜜向你抱怨,最近和男朋友关系不好,怎么办?\n你说,我也不太喜欢他,不喜欢就换一个呗,反正你还年轻...\n也许,人家两口子只是昨天的晚饭,因为盐放多了而拌嘴…\n比如,员工向你提意见:客户说我们包装太丑了,能不能改一改?\n你说,那我们就重新找个设计师设计一个新包装,替换掉现在的!\n也许,事实情况是1000个客户才1个人反应,其他人都还挺喜欢...\n因此,要解决一个问题,你得先弄明白问题到底是什么,别急于给方案。\n不然,讨论的过程,就会变成鸡同鸭讲,或者用高射炮打蚊子,发现了症状,却下错了药...\n那么,我们该如何精准的描述一个问题呢?\n☆ 如何描述一个问题\n第一步:明确期望值(B)\n你的目标是什么?正常的情况应该是如何的?这个目标是可衡量的吗?\n第二步:精准定位现状(B’)\n前面说的几个例子都比较简单,现状很容易描述。可现实情况可没那么简单,要清晰的描述目前所处的位置,并不是一件容易的事。\n因为现状往往不是单一维度的,需要牵涉到许多方面,比如文中提到的团队业绩问题,我们在描述现状的时候,仅仅说业绩数字是不够的,我们得从历史销售数据、团队人员状况、产品质量、渠道营销、市场环境、竞争对手...等等多个方面来全面描述。\n而且,描述的时候,你还得注意区分事实与观点:\n什么是事实?什么是观点?\n比如:今天好冷啊!\n请问,这个是事实,还是观点?\n你说,这当然是事实啊,我都已经冷得发抖了,你是不是眼瞎?\n不对!\n冷,是观点,不是事实。\n那什么是事实?\n现在气温=0℃,这个才是事实。\n至于0度的时候,你觉得冷,还是不冷,每个人的感受是不同的。\n所以,这个体感的「冷」就是观点。\n**我们在描述现状的时候,需要用大量的「事实」来构筑,而不是「观点」。**不然现状就会变得很模糊,你也就不知道现状与期望的落差(B’→B)具体在哪里,给出的解决方案就自然会有偏差。\n第三步:用(B'→ B)这个落差,精准描述问题\n下一次,请记得不要再问出类似于「你的业绩那么差,打算怎么办?」这样模糊的问题,因为你认为的差,和他认为的差,也许并不一样。\n在他的眼里20%的下跌,也许算正常波动,而你却已忧心忡忡。所以,你想让他给出方案,而听到的却是感觉他在不断寻找借口...\n你们在讨论的,其实并不是该如何提升业绩的方法,你们在讨论的是,到底什么才算“差”…\n那应该怎么问?\n你应该问:你之前三个月的业绩分别是100万,110万,105万,而这个月变成了80万,我们来讨论一下,下个月如何能做到120万?\n这样,问题就会很聚焦,开口的第一句话,也许就是个好办法!\n一个问题,就像是一盏路灯,只会照亮下方的特定区域。\n你想要的答案,就像是一把遗失的钥匙,如果你想要找到它,就必须打开它上方的路灯才行。\n但如果你问错了问题,就像是开错了灯,就永远也找不回那把钥匙了。\n\n提出一个精准的问题,是你能找到正确答案的第一步,也是最重要的一步!\n好, 问题描述清楚了,那我们该如何寻找答案呢?\n☆ 如何寻找答案\n从现状(B’)出发,找寻一条从(B’→ B)的路径吗?\n比如:\n人体正常温度(B)= 37℃;\n现状(B’)= 38.5℃;\n精准的问题描述就是:\n我现在体温是38.5℃,比正常体温(37℃)的高了1.5℃,我发烧了,该如何降至(37℃)?\n如果你的解决方案是从(B’)出发,那么得到的解决办法可能就是:\n\n冰敷,直接对头部降温\n吃大量的冰块,把体温降下来\n\n可真正的问题是38.5°→37度,这个差额吗?\n不是!\n发烧,只是表面问题,而本质问题也许是细菌感染...\n表面问题,只是由本质问题导致的症状,而我们常常把症状当成了问题本身,于是急于去消除它,而忽略了本质问题。\n结果就是头疼医头,脚疼医脚,就算温度暂时降下来了,过段时间又会升上去,真正的问题依然存在…\n别觉得这个案例看上去很弱智,在现实生活中,我们用的往往就是这种弱智策略…\n\n离职两个员工,那就再招两个!\n竞争对手降价,那我们也降价!\n员工状态消极,那就天天打鸡血!\n一说话就吵架,那就都不说话了!\n……\n\n看似当时有效,可没过多久,同样的问题又会反复出现,或者又引发了新的问题….\n怎么办?\n我们该如何穿透表面问题,寻找本质问题呢?\n☆ 如何找到本质问题?\n答:别盯着问题看!\n遇到问题,你要掌握足够的信息来精准的描述问题,这是第一步。\n但要解决这个问题,一定别盯着问题看,盯着症状是找不到答案的,或者只能找到治标不治本的方案。\n这就像是门被锁住了,钥匙一定不在门上,你盯着钥匙孔看是没用的,你要到别处去找钥匙!\n那去哪里找呢?\n我们先来看一下这个(B’)是如何产生的。\n比如,我们设定,公司本月业绩的(期望值B)=100万;\n然后怎么办?\n每月的业绩又不会自己完成。所以,我们同时要制定一个实现它的方法,我们假定这个方法是(A);\n那么,理想的状态应该是:做了(A),就能完成(B)。\n\n\n注:这里说的方法,包括了与之关联的人、事、物等等\n\n可现在做了(A)之后,并没有达到预期结果(B),而是达到了(B’),这就产生了(B’→B)的这个落差。也就是我们看到的表面问题,或者称之为症状。\n\n然后我们就开始分析,(B’)为什么会产生?\n结果发现了有一家讨厌的竞争对手,他们降价了!\n这个因素,在我们当时制定(A)的时候,没有考虑进去,是一个在过程中突发的变量,我们称之为(C)。现状(B’)的出现,它脱不了干系!\n\n至此,我们发现,现状(B’)并不是凭空出现的,而是由三个因素的共同影响下所导致:\n\n**A:为了实现(B)的结果,所使用的方法。**如果方法是错误的,目标自然无法达到。\n**B:期望值。**目标设置不当,或者目标设定过高,那么即便完美做到了A,这个目标也无法达成;\n**C:过程中出现的变量。**方法和目标都没有问题,可是出现了意料之外的事,也有可能导致目标无法达成…\n\n因此,(B’)只是症状,而导致这个症状出现的是ABC这三个因素,他们才是更本质的问题。\n所以,要解决这个问题,不能盯着(B'→ B)看,而是要透过(B’)去看ABC,我称之为「透析三棱镜」。\n\n\n如果你看到这里,觉得还不错,请先帮忙点个赞,下面,我接着来说一下这个三棱镜具体该怎么使用...\n\n☆ 透析三棱镜B:校准目标\n\n遇到问题,就习惯性的找原因,找解决办法,难道你就没想过,是目标本身错了吗?\n啥?\n你这是找借口好吧!\n达不到说目标有问题?\n达不成就得努力,就得坚持,就得学习啊!这有什么问题吗?\n对,你说的没错,但前提是,你得先有个正确的目标...\n比如,如果你的目标是「幸福」\n这就不是个正确的目标。\n请问,你如何衡量达到「幸福」了?\n幸福,没有标准,每个人对它的定义也不同。既然无法衡量,你也就无法知道与现状落差具体在哪,找不到落差,你甚至连问题是什么都不知道!\n\n是存款不够多?还是房子不够大?\n是老公不够帅?还是儿子不够慧?\n还是总有个别人家的老公和隔壁家的孩子,让你心烦,让你躁?\n\n没有清晰的目标,你认为的问题就会永远存在,永远达不成,整天感觉自己不幸福,却不知道该怎么办...\n随之而来的,是间歇性的嫉妒,和持续性的焦虑…\n再比如,你唱歌五音不全,却给自己定了一个目标,要一年之内成为一名职业歌手,并举办一场万人演唱会…\n然后你不断学习,刻苦练习,半年后,你报名参加了《中国好声音》,想向他们展示你这半年来的成果,更想就此一举成名,踏上梦想的舞台...\n你一开嗓,就霸气十足,跨跃两个八度,直接把评委们都给看傻了...\n终于…\n你被当成观众捣乱现场秩序,请出了舞台...\n为什么会这样?\n是你练习的方式不对吗?还是学习的课程不够专业?\n都不是,而是这个目标对目前的你来说,不切实际...\n所以,一个错误的目标,会让你的所有努力,都化为泡影。\n那怎么办呢,如何设定一个正确的目标?\n设立目标的SMART原则\n设立目标,一定要遵循SMART原则,什么是SMART原则?\n\nS:Specific,明确的,具体的\n\n比如刚才提到的目标「我的目标是要幸福」\n这个目标本身没有错,只是办不到而已,因为幸福的定义不明确,所以不知道该做什么才能达成。那怎么办呢?\n你想要幸福,就一定要有所行动,因此,你可以把这个目标用清晰明确的行动指引来替代。\n比如:我的目标是有一份稳定的工作,有一个爱自己的老公,每周能一起去看次电影,每年去旅行一次。\n\nM:Measurable,可衡量的\n\n目标是否达成,需要可以被衡量,比如你说「我们的目标就是让客户满意」\n那么怎么样才算满意呢?\n这个无法衡量。\n你需要加上一组数据维度,比如说「用户好评分,在9.5分以上」,这样就能衡量是否达成了。\n\nA: Achievable,(自力)可达到的\n\n你不能定一个不可实现的目标,比如前面说的唱歌的例子,那个目标是不错,但是从五音不全,到成为歌星,这个目标离你的现状太远,遥不可及,你几乎不可能在1年之内实现。\n你可以先定一个可实现的小目标,比如参加唱歌培训班,并通过毕业考试。然后在K歌软件上上传翻唱录音,获得100个粉丝,100个点赞。\n如果这个目标能达成,再定一个远一些的目标,就会比较靠谱。不然就会因为目标距离太远,而让自己始终处在焦虑的状态,也不知道下一步该如何改善…\n这里要强调的一点是,目标的达成,一定是自己的力量可以控制的过程,而不能把目标达成与否寄托在他人或者你不可控的事情上。\n比如,目标定为「下半年能够升职」,或者是「他能更喜欢我」,这些你不能控制,因为决定权在对方,你可以改成「连续两个月达到团队业绩第一名」、「提升自己对他的吸引力」...\n\nR:Rewarding,完成后有满足感的\n\n不能设定太远的目标,那我就设定一个「近一些的,容易实现的」目标可不可以呢?\n那你就需要衡量,当你完成这个目标的时候,是否能够满足你的存在感知层?\n\n存在感知层的概念,请参考第五课《脱了衣服你还是谁?》\n\n太近、太容易的目标,即便完成,你也不会有愉悦感和满足感,那么这就不是一个好目标,会让你在过程中失去对它的渴求,也就没有了动力。\n\nT:Time-bound,有时间限制的\n\n一定得有时间限制,不然任何目标都没有意义,比如「我的目标是赚100万」,那是准备多久达到呢?1个月?1年?10年?还是50年?\n不同的时间限制,会导致你思考的方式、制定的计划完全不同。如果没有时间限制,这个目标就会成为一句口号,起不到任何作用。\n除了这5点之外,你在制定目标的过程中,还得注意以下两点:\n\n要用正面语言去描述:\n关于「正面语言」的这个知识点,你可以参考第十三课《你的大脑,是不是被封印了?》\n你的目标不应该伤害他人或者你的其他目标,要保持整体的平衡。\n\n区分目标和手段\n除了目标要遵循「SMART原则」外,你还得注意区分目标和手段...\n\n我们使用方法A来达成目标B,但往往在过程中,却把A本身当成了目标,这是怎么回事?\n就比如读书这件事,你定了一个目标,一年要读50本书。\n然后呢,具体要看什么书?\n历史?商业?还是文学?找不到方向…\n年中的时候,发现才读了10本书,下半年就开始奋起直追。\n到了年底,终于读完了50本书了,然后呢?\n好像也没学到什么,读完这50本书能干吗呢?\n还是一脸迷茫…\n为什么会这样?\n那是因为,读书是手段,并不是目的。\n你不应该问:“读书是为了什么?”\n而是要问:“为了什么,我们需要读书?”\n\n可能是为了要解决某个具体的问题;\n可能是为了要写一篇学术论文;\n也可能是为了要准备一场重要的演讲…\n\n这样的读书,才能有效果。\n读书,是让你达成某个目标的手段, 但我们却常常把它当成了目标本身。\n再比如,有两个人在图书馆争吵:\n一个人要关窗,一个人要开窗,两个人争吵不休...\n图书馆馆长走了过来,分别问他们,为什么要开关窗啊?\n\n其中一人说:我要开窗,是因为天气太热了,想要透透气,吹吹风;\n另一个人说:我要关窗,是因为外面噪音太大了,影响我专心看书;\n\n结果,馆长把窗户关上,拿来了电风扇,两个人的问题就都解决了。\n关不关窗是手段,开/关窗后想要达到的结果才是目的。在不伤害其他人的情况下,别纠结手段,达到目的即可。\n关于这一点,在谈判中也比较常见:\n谈判中的双方,经常就某一价格问题,彼此僵持,一个要更便宜些,一个死活不降价,怎么办?\n那就是把手段当成了目的。\n我们要降价,对方不肯降价,可能都是为了要达到彼此公司能有更高利润的目的。那么,你谈判的焦点,就应该放在如何帮助对方提高利润上,而不要局限于眼前这个产品的价格上。\n比如,你们公司的网站流量很大,那么你就可以和对方说,价格我们给不了更多了,但是可以让你们公司的广告免费出现在我们的网站上,我们网站的流量非常高,这能让更多的用户了解你们,提高你们品牌的知名度。\n这样,你能用低价购入对方的产品,对方也能通过你的网站提升自己的总收益,这是一个双赢的方案。\n以上这些,就是因为目标的错误,而导致的问题。\n所以,当你遇到一个问题的时候,第一步应该先检查一下的,你的目标是否符合SMART原则?你是否把手段本身当成了目标?\n目标不对,什么都不对!\n☆ 透析三棱镜A:重构方法\n\n第二步,再来看(A)\n(A)是什么?\n(A)是你为了实现(B)所用的方法。(这个方法包括了与之相关的人、事、物)\n当出现了现状(B’),我们会习惯性的再找一条从(B’)到(B)的途径,其实这是治标不治本的方法,结果常常让同样的问题重复出现,这个前面我们已经说过。\n\n从这个示意图中我们可以看到,现状(B')不会平白无辜的出现,而是由原来的解决方案(A)导致的。如果不改变原有的解决方案,现状就很难改变。\n洋务运动 Vs 明治维新\n1861年,清政府开始了一段长达30年的洋务运动,学习西方人的先进技术,可最终失败了;而几乎在同时期的日本,开始了明治维新,同样也是学习西方,结果却大获成功,一举超越中国,跻身世界列强,这是为什么?\n洋务运动的指导思想是「师夷制夷、中体西用」这八个字,什么意思呢?\n师夷制夷,是「师夷长技以制夷」的简写,意思是要学习西方的长处,也就是他们的科学技术,学会了就可以反过来对付他们。\n可后面这四个字「中体西用」是什么意思?\n也是一句简写,原话是「中学为体,西学为用」,意思是国家和社会的主体结构,还是维持原来的封建体质,维持儒家文化,这些不能动摇,在这个前提下,我们学习并应用西方的先进技术,提高国力。\n听着是挺好的,洋务运动刚开始的时候,确实也办的风风火火的,可越到后面阻力越大,这是为什么?\n北洋水师,装了洋枪洋炮,号称亚洲第一水师,可在甲午海战中,被打的几乎全军覆没,这又是为什么?\n这个就是在不改变原来A的情况下,强行去改(B’)。\n\n看上去「表面问题」很快得到了改善,但是原来的A并没有动摇,那些隐藏在表面之下的「本质问题」依然存在。\n洋枪洋炮是换上了,可应该如何使用?士兵该如何训练?现代战争该如何打?\n洋枪洋炮是能自己仿造了,可质量如何保证?产能如何提高?时间长了如何维修和更新?\n这些问题,需要国家的政治、军事、经济、商业、教育等一同改变,才能得以解决,并不是借来一身高级西装穿上,就变成CEO了…\n看似表面光鲜,实则满目疮痍,等真正上了战场,才发现是个空心鸡蛋,晚了…\n这就好比,你明明种了一棵苹果树,已经长了一半了,你现在想改成葡萄树。但是呢,你又不砍掉苹果树重新种,而是直接在苹果树上挂葡萄,这个葡萄由于无法吸收树干给予的养分,或者营养成分不匹配,葡萄很快便枯萎了。\n反观日本的明治维新则不同:\n他们不仅仅是在科学技术、军事武装上学习西方,而是全盘的西化。\n建立新政府,改为君主立宪制政体,经济上推行「殖产兴业」,学习欧美技术,进行工业化浪潮,并且提倡「文明开化」、社会生活欧洲化,大力发展教育等等...\n这是直接在(A)上动刀,真正的推动了国家的整体变革。\n\n所以,想要大幅度改变现状,或者达成全新的目标,就得把原来的(A)一起改了,而不是在(B’)点上转弯。\n中国之后的崛起,也是因为原有的(A),被彻底摧毁了,虽然代价是惨痛的,但要从本质上解决问题,就不得不这样做…\n重复原有的方法,只能得到同样的结果;想要有不同的结果,就需要用不同的方法。\n具体怎么做呢?当发现问题后,如何调整(A)?\n回到开头的案例,王小锤的团队,离开了2名重要伙伴。不应该马上给出解决方案:再补两名销售。而是要回过头,去看看王小锤平时是用什么方式经营团队的,也就是原来的(A)是怎么样的?\n\n管理方法是什么?责权利有没有对等?是否用了情境管理?\n团队结构是怎么样的?合适的人有没有放到合适的位置?\n激励机制能否激励到所有人?是资源分配不公平?还是保健因素没给到?\n….\n\n是其中的哪个部分导致了员工的离开?\n如果这些「导致员工离开的原有系统」不改变,只是单纯的再补2个新人,那么依然还会有新的员工继续离职。\n调整(A)需要大量的背景知识和正确的思维方式,才能找到适合的解决办法,每个问题都有其独特性和不同的时空背景,需要具体问题具体分析。并不是我今天能在这里给你说一套,就能适用于所有症状的。\n你平时看的大量方法论书籍,以及我们之后要讲的许多课程,都是在讲各种(A),这些就像是不同的药丸,当你能够快速找到问题本质,就能在这些药丸中找到适合的来对症下药了。\n具体解决问题的思路和方法,我们会在本季度课程中的第三模块,分多节课详细讲解。\n☆ 透析三棱镜C:消除变量\n\n再来说三棱镜的第三面:变量(C)\n如果(A、B)都没有问题了,(B’)还是存在,那么就一定出现了变量(C)。\n这个(C)可能是内部变量,比如,发现原定计划(A)中的某个人并不能胜任该工作,或者团队执行力比预期的要低。\n这个(C)也可能是外部变量,比如,你平时非常注意身体的保养,控制饮食,保持运动,可还是感冒发烧了,那就不是(A)有问题,而是有可能被病毒感染了,这个不可预料的病毒入侵,就是变量(C)。\n\n那么我们该如何找到(C)呢?\n首先,你要建立一个寻找问题的基本思考框架,叫做:象、数、理。\n这三个词出自于《易经》,不过可以用作分析问题的口诀,「象、数、理」是什么意思?\n意思是:任何一个「现象」背后一定有「数据」,任何「数据」的变动,背后一定有「道理」。\n也就是说,当你发现某个现象后,你要赶紧去找相关的数据,然后用「数据」来说明问题,这可以让你对事情从感性认知变成理性分析。\n面对一个客观问题,要避免使用“我感觉….”这样的表述方式,比如:我感觉最近用户的投诉多了… 这样的反馈没有任何意义,这只是你的「观点」,不是「事实」,这点前文已经讲过,你要用「数据」来说明。\n比如:上个月我们的销量是1000单,共接到2个投诉电话,投诉率为「2‰」;这个月我们卖了3000单,却接到了20次投诉电话,投诉率为「6.7‰」,比上个月足足提高了3倍多,这个问题需要引起我们的重视!\n有了这个数据够不够呢?\n还不够,你要继续挖掘更细的数据,比如:这20个投诉电话,分别投诉了哪些内容?\n然后你发现,其中有19个投诉了产品质量问题,有1个投诉了物流问题…\n当然你还可以继续追问下去,比如具体是哪些部位的质量问题?占比各是多少?这些产品分别是什么时间生产的?等等…\n总之,把现象背后的数据分解的越细,看到的问题就会越精准。\n有了明确的数据,我们才能寻找「导致数据变化背后的道理」是什么。\n怎么找到数据背后的道理?\n我们可以使用「5Why提问法」\n也就连续追问5个为什么,来寻找这个数据异动背后的原因(5只是一个象征性的数字,意在提醒你,别拿到第一个答案后就认为是全部,而要继续往下深挖)比如:\n“为什么这个月的次品率是上个月的三倍?”\n“因为最近销量突然变大,这个月开始日夜两班倒,晚上的次品率比较高”\n“为什么晚上的次品率比较高?”\n“ 因为晚上品控把关不严”\n“为什么晚上会品控把关不严?”\n“ 因为工人们晚上都在偷偷看手机”\n“为什么半夜加班会偷偷看手机?”\n“ 因为最近正好是世界杯..”\n原来,世界杯,这个外因,导致了你产品质量的下降!\n然后怎么办?打电话给国际足联,让他们把世界杯取消了吗?\n发现根本原因后,你要把之后的改善行动落实在「自己可以改变」的事情上,你无法让世界杯暂停,但却可以让工人们不能携带手机进入工厂,这样问题就能解决了。\n☆ 小结:如何穿透现象看本质?\n今天,我们讲了分析问题的基本框架:透析三棱镜。\n我们太喜欢给建议,却往往还没弄清楚问题到底是什么。问题的本质是「期望」与「现实」的落差,因此,如果要解决问题,首先得弄清楚期望是什么,目前现状又是如何,这样才能精准定义问题所在。\n明确的问题,才能得到正确的答案,这是第一步。\n而问题并不会平白无故出现,它是由「目标、方法、变量」这三个因素共同影响产生:\n\n你可以用「透视三棱镜」的方法,找到隐藏在表面问题下的本质问题。\n\n第一步,校准目标B\n目标要符合SMART原则,同时要避免把手段当成目标;\n第二步,重构方法A\n现状是由原来的方法导致的,因此,想要改变现状,不是从现状出发,添加一个新的解决方案,而是回过头,重构原来的方法系统。\n第三步,消除变量C\n如果AB都没有问题,问题依然存在,一定存在着变量,你可以通过「象、数、理」这个基本框架来寻找它,并通过5Why的提问方法,挖掘真正的原因。\n在电影《教父》的原著中,作者马里奥·普佐有一句经典的旁白:在一秒钟内看到本质的人,和花半辈子也看不清一件事本质的人,自然是不一样的命运。\n\n祝你从今天开始,也能一眼看透本质,开启不同的命运!\n","description":"在电影《教父》的原著中,作者马里奥·普佐有一句经典的旁白:在一秒钟内看到本质的人,和花半辈子也看不清一件事本质的人,自然是不一样的命运。"},{"title":"使用夸克网盘搭建emby","url":"https://qixin.ch/posts/emby/","body":"使用开源工具挂载夸克网盘的WebDAV服务\n\n\n下载工具\nwget https://github.com/chenqimiao/quarkdrive-webdav/releases/download/v1.3.3/quarkdrive-webdav-x86_64-unknown-linux-gnu.tar.gz\ntar -zxvf quarkdrive-webdav-x86_64-unknown-linux-gnu.tar.gz\n\n\n\n运行工具\nquarkdrive-webdav --quark-cookie '你的cookie' -U '用户名' -W '密码' -p 8080\n\ncookie可以在夸克网页登录后通过控制台获取\n\n\n设置开机启动\ncat <<EOF > /etc/systemd/system/quark.service\n[Unit]\nDescription=Quark Service\nAfter=network.target\n\n[Service]\nType=simple\nExecStart=/root/quark/start-quark.sh\nRestart=always\nUser=root\n\n[Install]\nWantedBy=multi-user.target\nEOF\nsystemctl daemon-reload\nsystemctl enable quark\n\n\n#!/bin/bash\n/root/quark/quarkdrive-webdav --quark-cookie "$(cat /root/quark/cookie.txt)" -U admin -W password -p 8082\n\ncookie比较长,可以放在/root/quark/cookie.txt中\n\n\n将WebDAV挂载到vps\n\n\n安装工具\ncat <<EOF >> /etc/systemd/system/clouddrive.service\n[Unit]\nDescription=Clouddrive Service\nDocumentation=https://github.com/cloud-fs/clouddrive\nAfter=network.target network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\n# 这里的 User 和 Group 可以指定特定用户运行,\n# 如果需要挂载 FUSE 文件系统且不涉及权限问题,root (默认) 最为方便。\n# User=root\n# Group=root\n\n# 重要:指定工作目录,否则 Clouddrive 可能找不到配置文件\nWorkingDirectory=/root/cd2\n\n# 指定启动命令的完整路径\nExecStart=/root/cd2/clouddrive\n\nMountFlags=shared\n\n# 停止时的操作(可选,Systemd 默认会发送信号终止)\nExecStop=/bin/kill -s SIGTERM $MAINPID\n\n# 崩溃或退出后自动重启\nRestart=always\nRestartSec=5\n\n# 环境变量(如果需要)\n# Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"\n\n[Install]\nWantedBy=multi-user.target\nEOF\n\n\n\n\n重启服务\nsystemctl daemon-reload\nsystemctl enable clouddrive\nsystemctl start clouddrive\n\n\n\n生成strm\n auto_symlink:\n image: shenxianmq/auto_symlink:latest\n container_name: auto_symlink\n restart: unless-stopped\n ports:\n - "8095:8095" # 管理后台端口\n volumes:\n # 映射配置目录\n - /var/www/config/auto_symlink:/app/config\n # 映射您的 davfs2 挂载源 (必须加 :rslave 否则容器内看不到内容)\n - /var/www/quark:/var/www/quark:rslave\n # 映射 strm 输出目录\n - /var/www/emby_strm:/var/www/emby_strm\n environment:\n - TZ=Asia/Shanghai\n user: "0:0" # 使用 root 权限以确保能读取挂载点\n\n配置Emby\n emby:\n image: emby/embyserver:latest\n container_name: emby\n restart: unless-stopped\n ports:\n - "8096:8096"\n environment:\n - UID=0 # 建议使用 root 避免挂载点权限问题\n - GID=0\n - GIDLIST=0\n - TZ=Asia/Shanghai\n volumes:\n # Emby 配置\n - /var/www/config/emby:/config\n # 关键:Emby 必须能访问 strm 指向的真实路径\n - /var/www/quark:/var/www/quark:rslave\n # 挂载生成的 strm 目录作为媒体库\n - /var/www/emby_strm:/media\n\n备注\n\ncd2挂载时设置允许其他用户访问权限\necho \"user_allow_other\" > /etc/fuse.conf\n破解emby\n\nwget --no-check-certificate https://cangshui.net/-down/-mysh/emby/emby4.8.11.0/emby-happy.tar\ntar -zxvf emby-happy.tar\n\ndocker cp ./connectionmanager.js emby:/system/dashboard-ui/modules/emby-apiclient/connectionmanager.js\ndocker cp ./Emby.Web.dll emby:/system/Emby.Web.dll\ndocker cp ./embypremiere.js emby:/system/dashboard-ui/embypremiere/embypremiere.js\ndocker cp ./MediaBrowser.Model.dll emby:/system/MediaBrowser.Model.dll\ndocker cp ./Emby.Server.Implementations.dll emby:/system/Emby.Server.Implementations.dll\n\n\nLinux 的 FUSE 挂载默认只允许执行挂载命令的用户(通常是 root)访问\n\n","description":"夸克+webdav+CloudDrive2+AutoSymlink+Emby自建影视库"},{"title":"使用115网盘搭建emby","url":"https://qixin.ch/posts/115emby/","body":"使用开源工具连接115网盘生成strm和刮削图片\n\n\n使用docker compose运行工具\nversion: "2.3"\nservices:\n qmediasync:\n image: qicfan/qmediasync:latest\n container_name: qmediasync\n restart: unless-stopped\n ports:\n - "12333:12333"\n - "8095:8095"\n - "8094:8094"\n networks:\n - all\n volumes:\n - ./config/qmediasync:/app/config\n - ./strm:/media\n environment:\n - TZ=Asia/Shanghai\nnetworks:\n all:\n driver: bridge\n\n\n\n配置刮削和同步\n\n打开http://localhost:12333\n配置刮削和同步\n\n\n\n安装emby server\n\n\n使用快乐版\nversion: "2.3"\nservices:\n emby:\n volumes:\n - ./config/emby:/config\n - ./strm:/data\n ports:\n - "8096:8096"\n networks:\n - all\n environment:\n - TZ=Asia/Shanghai\n # 推荐:省略 UID/GID=0,以非特权用户运行\n # user: "1000:1000" # 如果需要指定用户,请使用非0的ID\n restart: always\n container_name: emby\n image: amilys/embyserver:latest\n\n\n\n配置反代\nemby.xx.xx {\n # 匹配 /refresh 和 /action 开头的所有请求\n @tools path /refresh /action/*\n handle @tools {\n reverse_proxy 127.0.0.1:18080\n }\n\n # 其他转发给 Emby\n handle {\n reverse_proxy 127.0.0.1:8095\n }\n}\n\n\n\n配置快速刷新媒体库的脚本\nimport subprocess\nfrom http.server import BaseHTTPRequestHandler, HTTPServer\nfrom urllib.parse import urlparse, parse_qs\nimport requests\n\n# --- 配置区域 ---\n# Python 服务监听配置\nHOST_NAME = "0.0.0.0" \nPORT_NUMBER = 18080\n\n# Emby 配置\nEMBY_BASE_URL = "https://emby.xx.xx"\nEMBY_API_KEY = "xx"\n\n# 脚本路径\nSHELL_SCRIPT_PATH = "/root/update_blog.sh"\n\n# --- 功能函数 ---\n\ndef get_emby_libraries():\n """获取 Emby 所有媒体库列表"""\n url = f"{EMBY_BASE_URL}/Library/SelectableMediaFolders"\n params = {"api_key": EMBY_API_KEY}\n try:\n resp = requests.get(url, params=params)\n if resp.status_code == 200:\n return resp.json() # 返回列表数据\n return []\n except Exception as e:\n print(f"获取媒体库失败: {e}")\n return []\n\ndef refresh_emby_library(item_id):\n """调用 Emby API 刷新指定库"""\n url = f"{EMBY_BASE_URL}/Items/{item_id}/Refresh"\n params = {\n "api_key": EMBY_API_KEY,\n "Recursive": "true",\n "ImageRefreshMode": "Default",\n "MetadataRefreshMode": "Default",\n "ReplaceAllMetadata": "false"\n }\n try:\n resp = requests.post(url, params=params)\n if resp.status_code in [200, 204]:\n return True, f"✅ 刷新指令已发送 (ID: {item_id})"\n else:\n return False, f"❌ 失败: {resp.status_code} - {resp.text}"\n except Exception as e:\n return False, f"❌ 请求错误: {e}"\n\ndef run_shell_script():\n """执行本地 Shell 脚本"""\n try:\n result = subprocess.run([SHELL_SCRIPT_PATH], capture_output=True, text=True, check=True, shell=True)\n return f"✅ 脚本执行成功:\\n{result.stdout}"\n except subprocess.CalledProcessError as e:\n return f"❌ 脚本执行出错 (Code {e.returncode}):\\n{e.stderr}"\n except Exception as e:\n return f"❌ 未知错误: {e}"\n\ndef get_html_page(message=None):\n """\n 生成动态 HTML 菜单页面\n message: 操作后的提示信息\n """\n # 1. 动态获取媒体库列表\n libraries = get_emby_libraries()\n \n # 2. 生成媒体库按钮 HTML\n lib_buttons_html = ""\n if libraries:\n for lib in libraries:\n lib_id = lib.get('Id')\n lib_name = lib.get('Name')\n # 链接指向 /action/refresh?id=xxx&name=xxx\n lib_buttons_html += f'<a href="/action/refresh?id={lib_id}&name={lib_name}" class="btn">🔁 刷新 {lib_name}</a>\\n'\n else:\n lib_buttons_html = '<p style="color:red">⚠️ 无法获取媒体库列表,请检查 API Key 或网络。</p>'\n\n # 3. 提示信息 HTML\n msg_html = f'<div class="alert">{message}</div>' if message else ''\n\n return f"""\n <!DOCTYPE html>\n <html>\n <head>\n <meta charset="utf-8">\n <meta name="viewport" content="width=device-width, initial-scale=1">\n <title>Emby 管理面板</title>\n <style>\n body {{ font-family: -apple-system, sans-serif; max-width: 600px; margin: 20px auto; padding: 20px; text-align: center; background-color: #f4f4f9; }}\n h1 {{ color: #333; margin-bottom: 20px; }}\n .card {{ background: white; padding: 30px; border-radius: 12px; box-shadow: 0 4px 15px rgba(0,0,0,0.1); }}\n .section-title {{ text-align: left; font-size: 14px; color: #888; margin-top: 20px; margin-bottom: 10px; font-weight: bold; text-transform: uppercase; letter-spacing: 1px; }}\n .btn {{ display: block; width: 100%; padding: 12px 0; margin-bottom: 10px; background: #007bff; color: white; text-decoration: none; border-radius: 8px; font-size: 16px; font-weight: 500; transition: background 0.2s; }}\n .btn:hover {{ background: #0056b3; }}\n .btn.secondary {{ background: #6c757d; }}\n .btn.secondary:hover {{ background: #545b62; }}\n .alert {{ background: #d4edda; color: #155724; padding: 15px; margin-bottom: 20px; border-radius: 8px; border: 1px solid #c3e6cb; }}\n </style>\n </head>\n <body>\n <div class="card">\n <h1>🛠️ Emby 管理中心</h1>\n {msg_html}\n \n <div class="section-title">媒体库操作</div>\n {lib_buttons_html}\n \n <div class="section-title">系统操作</div>\n <a href="/action/update_blog" class="btn secondary">📝 更新博客脚本</a>\n \n <div style="margin-top: 20px; font-size: 12px; color: #ccc;">\n <a href="/refresh" style="color: #ccc; text-decoration: none;">刷新页面</a>\n </div>\n </div>\n </body>\n </html>\n """\n\n# --- HTTP 处理逻辑 ---\n\nclass RequestHandler(BaseHTTPRequestHandler):\n def do_GET(self):\n # 解析 URL 和 参数\n parsed_url = urlparse(self.path)\n path = parsed_url.path\n query_params = parse_qs(parsed_url.query) # 结果类似 {'id': ['708'], 'name': ['Movie']}\n\n response_content = ""\n \n # 1. 访问首页\n if path == '/refresh':\n response_content = get_html_page()\n\n # 2. 动态刷新媒体库 /action/refresh?id=xxx\n elif path == '/action/refresh':\n lib_id = query_params.get('id', [None])[0]\n lib_name = query_params.get('name', ['未知库'])[0]\n \n if lib_id:\n success, msg = refresh_emby_library(lib_id)\n # 操作完成后,返回带有结果提示的首页\n response_content = get_html_page(message=f"{lib_name}: {msg}")\n else:\n response_content = get_html_page(message="❌ 错误:缺少媒体库 ID")\n\n # 3. 更新博客\n elif path == '/action/update_blog':\n msg = run_shell_script()\n response_content = get_html_page(message=msg)\n\n # 4. 404\n else:\n self.send_response(404)\n self.end_headers()\n self.wfile.write(b"404 Not Found")\n return\n\n # 发送响应 (HTML)\n self.send_response(200)\n self.send_header("Content-type", "text/html; charset=utf-8")\n self.end_headers()\n self.wfile.write(response_content.encode('utf-8'))\n\nif __name__ == "__main__":\n server = HTTPServer((HOST_NAME, PORT_NUMBER), RequestHandler)\n print(f"Server started at http://{HOST_NAME}:{PORT_NUMBER}")\n try:\n server.serve_forever()\n except KeyboardInterrupt:\n pass\n server.server_close()\n\n\n\n效果如下:\n\n设置刮削\n\n\n元数据下载语言: 选中文,这里是指刮削出来的影片资料的语言。\n国家: 选China或者美国都没啥影响\n图像下载语言: 我选的是英文,因为我的国语电影和外语电影分为两个库。这里可以根据自己的喜好来,如果喜欢海报图片为中文的就选中文,但是中文的海报上往往会带一大片的上映广告信息。\n启用实时监控: 打开,当媒体库内有新文件下载完成时Emby会自动进行扫描和刮削\n\n\n\n元数据读取器: 打开,读取本地NFO文件,用来读取使用本地TMM或者Radarr刮削生成的文件\n元数据下载器: 给TMDB和The Open Movie Database打勾并点击右边的箭头把它们移到上面。TMDB优先,负责刮削元数据;OMDB负责刮削评分信息\n从元数据下载器导入合集信息: 打开,并在下方选择要自动整理合集的数量。一般选2,就是影片在TMDB刮削到合集信息,且本地有2部以上的系列作品时自动生成合集。\n\n\n\n图像获取器: 选择TMDB和Fanart,Fanart质量较高但需要科学,TMDB改了HOST就可以获取到。万剑归宗之刮削大法!史上最全从Emby命名规则到刮削设置一条龙图文教程!\n将媒体图像保存到文件夹中: 打勾,刮削到的图像会存在文件夹里方便查看\n\n\n\n获取器设置: 这里设置想要抓取的图像类型,我是全部打上勾了。下面设置想要抓取的数量和图像大小,默认是1280太小了,建议修改成1920。\n\n\n\n视频预览缩略图: Emby会使用FFMPEG抓取视频预览图,也就是你鼠标放在时间轴上时显示的预览图。也会显示在影片详情页的章节里。\n字幕下载: 我不推荐使用Emby来下载字幕,但是有需求的话可以打开,这里的设置根据实际情况选择即可。\n\n\n\n元数据下载器: 我是全勾上了,因为我把这几个API全部加入了强制代理。\n\n\n\n图像获取器: 我优先使用Fanart保证获取的质量,如果是修改HOST方式请只选用TMDB\n获取器设置: 参照电影的设置即可\n\n网盘资源\n\nCool Online Emby\n影巢\n盘搜\ncms\ncms增强\n\n备注\n\n脚本中EMBY_BASE_URL需要替换为自己的emby地址\n脚本中EMBY_API_KEY需要替换为自己的emby api key\n脚本中SHELL_SCRIPT_PATH需要替换为自己的博客更新脚本路径(懒得删除代码了)\n\n","description":"115网盘支持302,视频流量可以不走vps,但要注意异地或多IP带来的封控问题"},{"title":"提升302emby起播速度","url":"https://qixin.ch/posts/fast-emby/","body":"\n我是用qmediasync搭建的,这是以下文档的前提,如果你不是用这个工具搭建的,可能会有差异。\n\n1. 问题描述\n最近搭建了一个115+strm+302emby服务(115网盘+STRM播放列表文件+302重定向的Emby服务),发现起播速度较慢,经测试发现是因为302多次跳转(Emby服务器每次都需要向115服务器请求直链),以及emby服务端的响应时间导致的。\n抓包效果,以及详情如下\n\n\n\n由于手机屏幕比较小只筛选了115的请求记录,具体流程如下\n\n加上其他的请求,起播速度约7秒\n每次请求的作用不一样(Range请求是HTTP协议中用于断点续传或部分内容请求的机制):\n\n第一次请求header中包含Range: bytes=0-,主要是获取视频的基本信息(码率、格式等),响应头中包含Content-Length: 750112694\n第二次请求header中包含bytes=855081591-,寻找文件尾部,检查文件完整性或读取位于末尾的索引信息\n第三次请求header中包含bytes=855029833-,回退一点点位置来读取特定的数据块(如某些 MKV 格式的 Cluster 数据段或特定的 Metadata 元数据段)\n第四次请求header中包含bytes=11768-,此时播放器已经完全了解了视频结构,知道前面的 0 到 11767 字节只是些描述信息,真正的视频内容(Data Ocean)是从 11768 字节开始的\n\n由于我的emby服务器在国外,所以响应时间比较长,导致起播速度较慢。从上面的分析可以看出,第一次请求时已经拿到了115的直链,后续的三次我们可以跳过emby服务器直接客户端请求115,这样可以显著提升起播速度\n2. 解决方案:动态捕获与 302 重定向\n可以保存第一次请求响应头中的115直链,后续的三次请求直接本地请求115,而不是通过emby服务器。\n现在很多代理工具都支持请求/响应改写脚本,我主要在手机上观看,使用Quantumult X(一款iOS平台的网络调试工具)来实现这个优化方案。\n1. 拦截emby部分请求\n# 1. 匹配响应:捕获第一轮请求返回的Location(115直链)\n# 当客户端发起视频流请求时,该规则会拦截响应头并调用emby_save_link.js脚本\n^https?:\\/\\/emby\\.xx\\.com(:443)?\\/emby\\/videos\\/\\d+\\/stream url script-response-header emby_save_link.js\n\n# 2. 匹配请求:拦截后续轮次的Range请求\n# 当客户端发起带有Range头的请求时,该规则会拦截请求头并调用emby_redirect_logic.js脚本\n^https?:\\/\\/emby\\.xx\\.com(:443)?\\/emby\\/videos\\/\\d+\\/stream url script-request-header emby_redirect_logic.js\n\n2. 保存115直链\nlet url = $request.url;\nlet headers = $request.headers;\nlet respHeaders = $response.headers;\nlet status = $response.statusCode || $response.status;\n\n// 获取请求时的 Range\nlet range = headers["Range"] || headers["range"] || "";\n// 获取响应中的 Location (115 直链)\nlet location = respHeaders["Location"] || respHeaders["location"];\n\nlet videoIdMatch = url.match(/\\/videos\\/(\\d+)\\/stream/);\nlet videoKey = videoIdMatch ? videoIdMatch[1] : null;\n\n// 日志记录调试信息\nconsole.log(`ID: ${videoKey} range:${range} status:${status} location:${location}`);\n\n// 只有在以下条件满足时才保存直链:\n// 1. 成功提取到视频ID\n// 2. Range请求是从0开始的(第一轮请求)\n// 3. 响应状态码是307(临时重定向)\n// 4. 响应中包含Location头信息(115直链)\nif (videoKey && range === "bytes=0-" && (status == 307) && location) {\n // 将直链保存到本地存储中,键名为"emby_115_" + 视频ID\n $prefs.setValueForKey(location, "emby_115_" + videoKey);\n console.log(`[Emby优化] 成功捕获直链 ID: ${videoKey}, Location: ${location}`);\n}\n\n$done({});\n\n3. 本地拦截emby请求转发到115\nlet url = $request.url;\nlet headers = $request.headers;\nlet range = headers["Range"] || headers["range"] || "";\n\n// 从URL中提取视频ID作为缓存键\nlet videoIdMatch = url.match(/\\/videos\\/(\\d+)\\/stream/);\nlet videoKey = videoIdMatch ? videoIdMatch[1] : null;\n\n// 核心逻辑:\n// 1. 如果是后续的Range请求(不是从0开始)\n// 2. 且在本地存储中找到了对应的115直链\n// 则直接将请求重定向到115直链,绕过emby服务器\nif (videoKey && range && range !== "bytes=0-") {\n // 从本地存储中获取保存的115直链\n let savedLocation = $prefs.valueForKey("emby_115_" + videoKey);\n \n if (savedLocation) {\n console.log(`[Emby优化] 命中缓存,ID: ${videoKey}, Range: ${range}, 转发至直链`);\n // 返回302重定向响应,将客户端直接引导到115直链\n $done({\n status: "HTTP/1.1 302 Found",\n headers: {\n "Location": savedLocation,\n "Access-Control-Allow-Origin": "*",\n "Cache-Control": "no-cache"\n },\n body: ""\n });\n } else {\n console.log(`[Emby优化] 未命中缓存,放行由VPS处理`);\n $done({});\n }\n} else {\n // 第一轮请求(Range: bytes=0-)或无Range请求,直接放行给emby服务器处理\n $done({});\n}\n\n3. 测试效果\n优化目标流程\n优化后的请求流程将跳过后续请求的Emby服务器环节,直接从客户端请求115直链:\n\n实际测试结果\n\n性能对比\n\n优化前:起播速度约7秒(受Emby服务器网络延迟影响)\n优化后:起播速度约3秒\n提升幅度:约57%的起播速度提升\n\n备注\n\n本方案主要解决公网302emby服务的起播速度问题,对于局域网内的Emby服务,由于网络延迟较低,优化效果可能不明显。\n视频的基本信息(如码率、格式等)仍需通过第一次请求获取,这是Emby播放器正常工作的必要步骤。\n该方案依赖于代理工具的脚本功能,不同工具的实现方式可能略有差异。\n可以使用神医助手提取媒体信息以及优化搜索\n\n","description":"302emby服务由于使用了302跳转,需要多次与emby服务端交互,导致起播速度较慢,本文介绍如何提升302emby起播速度。"},{"title":"漫威电影宇宙观影顺序","url":"https://qixin.ch/posts/mcu/","body":"1. 剧情时间线顺序 (Chronological Order)\n起源阶段:\n\n\n《美国队长 1:复仇者先锋》 (发生在 1940 年代)\n\n《惊奇队长》 (发生在 1990 年代)\n\n第一阶段:\n\n\n《钢铁侠》 (发生在 2008 年代)\n\n《钢铁侠 2》 (发生在 2010 年代)\n\n《无敌浩克》 (发生在 2012 年代)\n\n《雷神》 (发生在 2013 年代)\n\n《复仇者联盟》 (发生在 2012 年代)\n\n第二阶段:\n\n\n《雷神 2:黑暗世界》 (发生在 2014 年代)\n\n《钢铁侠 3》 (发生在 2013 年代)\n\n《美国队长 2:冬日战士》 (发生在 2014 年代)\n\n《银河护卫队》 (发生在 2014 年代)\n\n《银河护卫队 2》 (发生在 2016 年代)\n\n《复仇者联盟 2:奥创纪元》 (发生在 2014 年代)\n\n《蚁人》 (发生在 2016 年代)\n\n第三阶段:\n\n\n《美国队长 3:内战》 (发生在 2016 年代)\n\n《黑寡妇》 (剧情紧接内战后)\n\n《黑豹》 (发生在 2018 年代)\n\n《蜘蛛侠:英雄归来》 (发生在 2018 年代)\n\n《奇异博士》 (发生在 2019 年代)\n\n《雷神 3:诸神黄昏》 (发生在 2020 年代)\n\n《蚁人 2:黄蜂女现身》 (发生在 2020 年代)\n\n《复仇者联盟 3:无限战争》 (发生在 2020 年代)\n\n《复仇者联盟 4:终局之战》 (发生在 2023 年代)\n\n第四及第五阶段(涉及多元宇宙):\n\n\n《蜘蛛侠:英雄远征》 (发生在 2021 年代)\n\n《尚气与十环传奇》 (发生在 2022 年代)\n\n《永恒族》 (发生在 2023 年代)\n\n《蜘蛛侠:英雄无归》 (发生在 2023 年代)\n\n《奇异博士 2:疯狂多元宇宙》 (发生在 2024 年代)\n\n《雷神 4:爱与雷霆》 (发生在 2024 年代)\n\n《黑豹 2:瓦坎达万岁》 (发生在 2024 年代)\n\n《蚁人 3:量子狂潮》 (发生在 2024 年代)\n\n《银河护卫队 3》 (发生在 2024 年代)\n\n《惊奇队长 2》 (发生在 2024 年代)\n\n《死侍与金刚狼》 (2024年上映,涉及多元宇宙与前福克斯宇宙)\n\n2025-2026 新上映:\n\n\n《美国队长 4:美丽新世界》 (2025)\n\n《雷霆特工队》 (2025)\n\n《神奇四侠:第一步》 (2025)\n\n\n2. 补充说明:Disney+ 剧集\n\n《旺达幻视》:观看《奇异博士 2》前必看。\n《洛基》第一、二季:理解 2024-2026 年“多元宇宙篇章”逻辑的核心。\n《猎鹰与冬兵》:观看《美国队长 4》前必看。\n\n","description":"按照上映时间的“无限传奇”(前三阶段)和“多重宇宙传奇”(第四阶段及以后)的阶段性顺序观看"},{"title":"暗淡蓝点 (Pale Blue Dot)","url":"https://qixin.ch/posts/andanlandian/","body":"\n\n背景: 1990年2月14日,旅行者1号探测器在距离地球60亿公里的地方,回眸拍摄了一张地球的照片。著名的天文学家卡尔·萨根(Carl Sagan)为此写下了这段不朽的文字。\n\n\n再来看一眼这个小点。就在这里。这就是家。这就是我们。\n在这个小点上,每一个你爱的人,每一个你认识的人,每一个你听说过的人,每一个人,无论是谁,都在此度过一生。我们所有的快乐和挣扎,数以千万自傲的宗教信仰、思想体系观念意识,以及经济学原理教义,每一个猎人或征服者,每一位勇士或懦夫,每一个文明的缔造者或摧毁者,每一位君王或农夫,每一对陷入爱河的年轻伴侣,每一位为人父母者,所有充满希望的小孩、发明家或探险者,每一位灵魂导师,每一个腐败的政客,每一个所谓的“超级巨星”,每一个所谓的“至高领袖”,每一位我们人类史上的圣人或罪人……我们的一切一切,全部都存在于这样一粒悬浮在一束阳光中的尘埃上。\n地球,只是浩瀚宇宙竞技场上一个小小的舞台。\n想想那些帝王将相扬起的腥风血雨,只为在荣耀和胜利中,短暂享受主宰着一个小点上一小部分的滋味。想想有些永无止境的残暴,竟然就发生在这个小点上某个角落里的一群人、与几乎分不出任何区别的同样这一个小点上的另一个角落的另一群人之间。他们之间的误解能有多频繁,他们之间想灭掉对方的愿望能有多迫切,他们之间互相的仇恨能有多炽烈。\n我们的装腔作势与妄自尊大,我们以为自己在宇宙中享有特权的幻想,都被这颗发着微弱蓝光的小点所挑战。我们的这颗星球,是一粒孤孤单单的微尘,被包裹在宇宙浩瀚的黑暗中。在我们有限的认知里,在这一片浩瀚之中,没有任何迹象表明救助会从别处而来帮助我们救赎自己。\n目前为止,地球是我们唯一所知有生命居住的世界。没有其他地方——至少是在不远的未来里,可供我们这一物种移民。我们能够造访,但尚不能常驻。不管你喜欢还是不喜欢,目前为止只有地球是我们的立足之地。\n","description":"寄蜉蝣于天地,渺沧海之一粟。关于旅行者1号拍摄的那张著名照片。"},{"title":"故障排除:永远不会过时的技能","url":"https://qixin.ch/posts/troubleshooting/","body":"我在多个领域所做的大部分工作,都可以归结为一项技能:故障排除。\n我将故障排除定义为系统地确定系统中不良行为的原因并修复它。\n故障排除通常是在明确学习\"技能\"的过程中潜移默化地学习的。故障排除很少被作为一项技能本身来讨论。但有效进行故障排除的许多方法是领域无关的。\n意识到我花在故障排除上的时间比构建或执行上的时间更多,并且故障排除技能可以与应用它的领域分开磨练,我决定尝试找出如何提高我的故障排除技能 - 从而提高我在多个领域的效率。\n我做故障排除的方式,主要归结为抓耳挠腮,用谷歌搜索错误信息,以及想出并测试假设以缩小搜索范围。但我经常发现自己犯了以前犯过的错误。所以当我进行故障排除时,我会尝试记住以下几点,以保持在正轨上并避免死胡同。\n步骤1:退后一步\n故障排除需要一定的心态。据我所知,它需要对系统底层结构的兴趣 - 用皮尔斯的话说,\"经典\"思维 - 耐心,对细节的关注,以及坚韧不拔。\n有时,即使在赶时间的情况下,缓慢、深思熟虑、冥想式地进行故障排除也更有效。\n很容易陷入被动的问题处理中,而没有停下来思考:这个问题的真正原因是什么?这里到底发生了什么?\n故障排除者是系统的一部分。因此,会有探针效应和传说中的海森堡bug。\n\n确保你在调整正确的弦\n任何弹过一段时间吉他的人都知道那种切身的感觉:意识到他们正在转动的是与他们正在拨弄的不同弦的调音器。难怪没有任何帮助!\n当试图修复一个系统时,在开始工作之前,我会做一些保证会有效果的事情。\n如果我认为我知道要切断哪根电线,我会先拉一拉它,确保它在另一端移动。\n当我在排查CSS bug时,我通常会先设置 * {color: red !important;},这样我就知道我写的代码在正确的文件中,并且实际正在运行!\n确定流程\n很容易花很多时间尝试\"修复\"问题。但那是简单的部分。困难的部分是理解系统,然后隔离并理解问题。\n我通常从\"东西\" - 电力、水、汽油、空气、力、数据、污水,或其他任何东西 - 如何流经系统,并在此过程中转化为不同的东西开始。\n输入、输出和转换是什么?流经系统的不同类型的东西可以被分组为半独立的子系统吗?\n在电气系统中,物理追踪布线通常很有帮助。在机械系统中,同样适用于输送液体或气体的管道,或控制电缆、凸轮、齿轮、链条和其他传导机械力的物品。在软件中,追踪数据。在社会动态中 - 祝你好运!\n\n观察症状\n应该发生什么,实际发生了什么,以及两者在哪里分歧?\n如果可能,我会根据症状缩小哪些子系统受到影响。如果我的汽车刹车灯不工作,问题可能是电气问题;如果汽车下面有油迹,可能不是电气问题。如果发动机无法启动,可能两种情况都有可能,需要更多调查。\n我理解系统的信念往往是故障排除的障碍。即使我\"对系统了如指掌\",我也不太可能完全理解它。即使是我构建的系统也由我没有构建的系统组成;即使看似简单的系统也无限复杂。(正如卡尔·萨根所说:\"如果你想从头开始做一个苹果派,你必须首先发明宇宙。\")\n隔离问题\n下一步是找出子系统在哪个步骤失败。\n我的基本方法:在系统上\"做科学\"。\n\n\n对问题形成假设。这可以是来自症状的直觉第一印象,或来自扩展观察的最佳猜测。\n\n首先排除最简单和最可能的问题区域。那些旨在被维护、以前失败过或受到机械应力的东西。好的系统设计成让可能坏掉的东西易于维护。例子:电气保险丝和断路器、皮带和链条、过滤器、各种端子和连接、I/O设备。\n如果没有简单的方法来猜测问题所在的系统区域,执行非正式的二分搜索。\n\n\n\n找到最简单的方法来证伪我的假设。一般来说,这意味着在我认为问题所在的位置的直接上游/下游\"切断\"系统,并在切断点测试功能。\n\n\n\n断开子系统\n当可能时,我会断开我正在调试的子系统。\n这有三个好处:\n\n它可以防止与系统其他部分的奇怪交互使诊断复杂化(一旦我让子系统自己工作,我可以将其重新连接在一起,看看它是否继续工作)\n它可以保护系统的其他部分免受我的愚蠢行为的影响\n它通常会缩短反馈循环\n\n或者不\n如果我不能(或不想)完全断开部件,另一种方法是在不同点探测 - 或切割和探测。\n如果我知道或可以直觉到系统正常运行时测试点处相关参数的可接受范围,实际值可以指示问题的位置。\n找到好的切割点\n我可以在多少个点\"切割\"系统同时保持功能以进行测试?\n火花塞是子系统之间切割点的一个例子。\n如果发动机无法启动,但我可以获得火花,问题可能不在电气子系统中。\n除了内部切割点外,我总是尝试在我负责的系统和世界其他部分之间的接口处进行测试。这可以帮助我确定是\"我的东西\"坏了,还是只是在尝试与坏了的\"其他人的东西\"交互时出错(这可能在我的能力范围内或之外)。尝试修复没有问题的东西会浪费很多时间!\n\n平衡获取信息和尝试修复\n应该在尝试修复问题上投入多少努力,在获取有关问题的信息上投入多少努力?\n如果我的直觉是对的,直接着手修复问题会快得多。\n但如果不是,从长远来看,系统地收集信息会更有效率。\n我们进入故障排除情况时,对我们面临的问题的\"难度\"有一个先验,这会告诉我们何时尝试直接修复问题,何时尝试收集更多关于它的信息。\n但我们的\"难度先验\"往往是错误的。所以我们需要基于个人倾向和领域专业知识,发展某种关于我们的故障排除难度先验可能有多准确的元先验。\n了解风险\n故障排除问题的风险可以从零(业余软件项目)到改变生活(医疗诊断)到存在性(AGI、核武器),这应该指导问题的处理方式。\n所以我尝试问自己:\n\n\n最糟糕的情况是什么?如果我搞砸了,风险是什么?我搞砸的可能性有多大?\n\n对故障排除者的危险:系统工作起来有多危险?是否涉及高压、易燃材料、有毒化学品、千斤顶或可能的数据丢失?\n对旁观者的危险:同上,但考虑爆炸半径的大小,以及旁观者对危险的潜在无知和缺乏安全设备。\n对系统的危险:这个系统有多脆弱?它可以更换吗?\n对他人的危险:这个系统行为不可预测的可能后果是什么?谁在这个系统的下游?\n\n\n\n尝试修复和不尝试修复的相对风险是什么?\n\n如果某件事已经危险地坏了,修复它相对更安全,即使修复它有失败的风险。\n\n\n\n系统属于谁?\n\n是我弄坏了这个系统吗?我有责任修复它吗?\n我是被付钱来修复它的吗?如果是,我成功、失败和灾难性失败的可能性有多大,客户知道风险吗?(我不再为没有备份系统的人提供志愿技术支持。)\n\n\n\n我如何减少这种干预的下行风险?\n\n一般来说,工作更慢更仔细(这样我就不会搞砸);在\"暂存\"而不是\" live\"系统上工作;备份系统。\n\n\n\n危险在这种情况下至少有四个组成部分:时间框架、强度、范围和物理性。最明显的危险是即时和物理的。但就伤害/益处而言,为主要投资银行处理关键代码可能在长期内同样具有物理风险;风险只是分布、延迟和不可见的。\n不要过度思考\n不要假设它很复杂。仅仅因为调试起来很复杂并不意味着原因很复杂。\n但也不要假设它很简单。\n保持耐心\n不言而喻。\n查找有关系统的信息\n根据定义,故障排除者超出了他们的深度。好的故障排除者必须习惯处于无知状态。\n需要什么信息以及如何获取信息,取决于系统和问题的细节。\n知道使用什么搜索引擎获取什么类型的信息\n有时(例如,机械,或钓鱼失败)我需要认识知道如何做的人,并给他们带一箱啤酒。\n其他时候,我需要知道如何使用库或手册。(案例研究:我母亲的斯巴鲁的电动车窗停止工作。各种汽车人试图修复它们。我检查了保险丝。但她有一个聪明的想法,不是只是浏览手册找保险丝,而是阅读手册。儿童安全锁打开了。)\n在现代世界,我主要需要知道如何使用搜索引擎。不同的搜索引擎用于不同的目的,谷歌不再索引许多利基网站。\n我可能需要一个LLM,因为我不知道如何用正确的术语表达我的问题,搜索特定领域的论坛来减少废话,如果是难以用语言描述的物理技能,搜索YouTube,或者直接搜索相关系统的文档/手册。\n知道如何使用高级搜索条件缩小搜索空间\n虽然它们都不是故障排除特定的,但如果你不熟悉搜索操作符,这里有三篇文章可以开始:\n\n如何在互联网上找到任何东西\nGoogle搜索操作符:完整列表(44个高级操作符)\n互联网搜索技巧\n\n知道如何扩大搜索空间并排除无关信息\n大多数系统会发出多种信息,相关性差异很大。\n在软件日志中,有一行行重复的 chatter,然后有一行提示我。通常,它会说\"error\"或\"fail\",或提到受影响的子系统。\n同样,发动机发出很多噪音。大多数噪音是正常的。相关数据是声音的变化。当预期的噪音从总噪音中减去时,剩下的是什么?问题的声音指纹。\n错误消息本身只有部分重要。\n大多数软件错误消息如果我逐字粘贴到谷歌中,会产生很少有用的信息,因为它们包含特定于我的设备的内容。我通常从完整的错误消息开始,减去明显的设备特定信息。如果没有结果,我会扩大搜索空间。我不再寻找有关特定版本的信息。我不再寻找有关特定硬件的信息。我甚至不再寻找有关特定软件的信息,然后我会在论坛上找到拥有不同笔记本电脑、运行不同应用程序但共享导致错误的依赖项的人。他们的修复可能不起作用,但它可能指向问题所在。然后我可以获取更多数据并重复该过程。\n学习钓鱼\n如果某件事需要修理,我可以尝试自己做,这可能很慢且效率低下。或者我可以让专家来做,这很快且容易。让别人解决我的问题的问题:我学不到多少。\n如果我有一个故障排除问题,并且对该领域一无所知,一个非常有效的方法是:\n\n找到该类型系统/问题的领域专家\n不是让他们为我修复它,而是让他们与我一起修复它。\n\n这在短期内对双方来说都更慢,有时更不有趣,但可以学到很多。下次我可能能够自己做。\n这是一个连续体,一端是看着他们修复它,另一端是我自己修复它而他们看着。我越动手,对每个人来说就越慢和沮丧 - 我被迫学习的就越多。\n从系统获取信息\n我从系统获取的信息越多,最好是在错误发生时,就越好。\n我从系统获取所有可能的信息:更多的输出,以及来自系统中更多点的更具体的输出。\n在软件中,这意味着日志记录,或在进程运行时附加调试器。\n在电子设备中,第一步通常是获取万用表,并检查不同点的系统状态。\n在机械方面,我不太擅长,我注意到我的哥哥通常打开引擎盖运行东西,同时密切观察、闻和听。\n\n埃里克·巴克在《与他人相处融洽》中写到了这与人们的关系。我们不擅长阅读人(即使我们认为我们擅长),少数有帮助的事情之一是与该人互动,以产生更多信息。\"从系统获取更多信息\"是少数科学验证的测谎方法之一(说谎者最终会自相矛盾)。相关地:许多人可以权威地谈论复杂主题,但两三个精心选择的深入细节的问题可以将真正的专家与那些只是重复他人表面意见以听起来令人印象深刻的人分开。\n当我们调试自己时,仅仅从系统获取信息的行为(记日记)有时就足以修复它。\n直觉系统的容忍度\n有时,在修复事物的过程中,我们会破坏东西,无论是意外还是因为无法避免。\n不同的材料有不同的容忍度。某些部件可以承受某些类型的损坏而不改变系统的功能。其他区域如果以同样的方式处理可能会导致整个系统失败。\n对于物理事物,需要机械直觉来施加正确的力,并理解哪些部件可以和不能承受损坏。孔或密封比外部外壳更敏感。\n与系统保持良好关系\n我注意到:不喜欢计算机的人在计算机方面往往效率低下;不喜欢人的人往往无法从他们那里得到他们想要的东西,除非他们擅长隐藏自己的感受。这听起来有些模糊,但我认为欣赏行为不当的系统的美丽和复杂性会使一个人成为更有效的故障排除者。将系统视为敌人会使它成为敌人。\n在我看来,敌人与对手不同。与系统的友好竞争,试图\"在游戏中击败它\",似乎不会损害故障排除。对手必须受到尊重和理解才能被击败。要避免的是\"坏狗\"式的愚蠢计算机不肯按我想要的方式做事的心态。敌人,当被憎恨时,会被剥夺他们的个性,成为自己的漫画;你不能故障排除一个漫画,因为它与实际系统不匹配。\n利用可用资源\n拥有正确的工具来测试、拆卸、修理和重新组装系统会有所帮助。\n在实践中,更重要的是能够即兴发挥,并基于底层形式而不是标签或先入之见找到工具和替换零件。\n缩短反馈循环\n为了修复系统,我需要能够重现问题。为了获得足够的关于问题原因的数据以可靠地重现它,我经常需要在不同条件下多次运行系统。然后,一旦我可以重现它,我通常需要再运行系统多次,每次调整参数,试图找出条件的哪个方面实际上触发了问题。\n有时,系统会有一些内置的延迟或 latency,使得没有复杂的步骤就难以重现错误。\n当这种情况发生时,我会问:\"有什么方法可以缩短反馈循环吗?\"\n在代码中,这可能是减少硬编码的超时,只处理子组件(带有虚拟输入和输出),在本地测试以便我不会访问网络,启用热重载,或自动化部署过程。\n对于电子设备,可能就像将万用表粘在端子上一样简单。\n一个有点可怜的例子:当故障排除时,我经常发现自己在连接缓慢的小手机上查找东西,或者在我正在修复的东西和关于我正在修复的东西的信息源之间来回奔波。将手册或计算机直接放在我工作的地方可以节省令人惊讶的时间。\n减少噪音\n在进行干预之前,我尝试减少系统中的混淆变量和\" sloppiness\"。\n断开子系统有助于此,因为与其他子系统的交互会混淆测试结果。\n缩短反馈循环也有帮助,因为时间延迟给其他变量在输入进入和输出出来之间影响系统状态的机会。\n写下来\n作家喜欢说\"写作就是思考\"。以下是我将写作用作故障排除工具的两种方式:\n\n\n像专业人士一样进行橡胶鸭调试:我通常可以通过起草论坛帖子而不发布它来解决我的问题。在我决定需要帮助的点上,阐明系统和问题的 salient 细节而不显得愚蠢所需的努力,高于我通常投入的努力。推论:在听起来我没有做过功课的情况下发表论坛帖子,也往往会让我超出解决看似微不足道的问题的时间/精力预算。\n\n\n** behold the trail of crumbs**:我发现写作和图表,虽然对许多故障排除项目有帮助,但对多会话故障排除项目至关重要。我高估了我对上下文的记忆,以及我多快能继续该项目。故障排除笔记文件,无论我写它时其中的信息看起来多么明显或不完整,都会留下面包屑 trail,我下次可以跟随。(我经常重复,逐字逐句,整个故障排除过程,找到问题 - 然后记得我几年前就故障排除了完全相同的系统,并得出了相同的结论;但有一些小问题,我未能订购或安装新零件。)\n\n\n通过向黑盒中放入特定内容并观察输出来查看内部\n尽管\"断开子系统\",有时我必须故障排除黑盒系统。一种方法是向它们提供非常具体的输入,并观察会发生什么。如果系统在某些输入上失败,采取以下两种方法之一可能会有所帮助:\n\n\n采取导致它失败的条件/输入,移除条件/输入的一个组件,并将其馈入系统。如果它仍然导致问题,移除另一个因素(可选地,恢复前一个因素)。重复直到剩下的只有真正导致问题的东西,或尽可能接近。\n\n\n采取一些已知良好的条件/输入。添加一个存在于导致失败的输入/条件中的因素。重复(一个接一个,或累加)直到系统失败。\n\n\n理解问题\n也许其中一个小部件烧坏了。但为什么它会烧坏?小部件在周二下午就烧坏是正常的吗?或者,是否有短路,或水损坏,或散热问题,或(如最近的情况)容易被附近的雷达击倒?\n如果某件事不应该失败,但它失败了,故事还有更多。\n在放入新零件之前,我想确信它不会遭受同样的命运。要么前一个零件规格不足,要么系统中的其他东西使它承受了过度的压力。\n解决问题\n一个被理解的问题已经大部分被解决,除非零件难以获得,或难以安装。\n\"修复\"某物通常是\"更换损坏的组件\"的同义词。\n我对问题和系统的理解程度决定了需要更换的系统部分有多大。\"零件更换者\"是对坏机械师的贬义词。一般来说,故障排除者越好,更换的组件越小。\n这些陈述可能都是真的:\n\n这个音响系统坏了。\n这个MP3播放器坏了。\n这个MP3播放器的耳机插孔坏了。\n这个MP3播放器的耳机插孔上的焊点坏了。\n\n我可以更换MP3播放器。我可以更换耳机插孔。或者,我可以重流一个焊点。结果将是相同的。\n虽然更换超过必要的部分是浪费和不优雅的,但一个好的故障排除者也需要知道何时放弃深入研究一个并不真正重要的问题的根源,并接受一个更资源高效的权宜之计。\n故障排除可以教吗?\n我从2024年5月开始间歇性地写这篇文章。也许我在自欺欺人,但我似乎在故障排除方面变得更好了。最大的变化是现在我费心。我接受否则无吸引力的故障排除问题以测试我的理论,无论我是否认为它们值得我的时间。并且因为我花了很多时间思考和谈论故障排除,我觉得我应该是某种当地专家,即使这个声誉只存在于我的脑海中,我也想不辜负它。\n如果我有预算,我会科学地测试这一点。我会招募一群人。一半会读这篇文章,另一半会读同样长度和风格但不是关于故障排除的东西。然后,两组都会尝试在像sadservers.com这样的网站上解决Linux服务器故障排除难题。哪一组会更有效?如果读这篇文章的人做得更好,实验可以在其他领域重复,看看故障排除技能如何推广。\n结论\n一旦我进入故障排除心态,大多数事情开始看起来像故障排除问题。这种系统-问题-解决方案的世界观在某些情况下是有效的,但它不是唯一的世界观,也不是对所有事情的最佳方法。\n当我意识到我正在处理一个故障排除问题并有意识地故障排除它时,它节省了很多时间。但同样重要的是要意识到并非所有事情都是需要解决方案的问题。\n一些故障排除故事\n\n汽车对香草冰淇淋过敏\nWi-Fi只在下雨时工作\n500英里电子邮件的案例\n钱花得值:工程师的短篇故事\n编辑Bash脚本时要小心\n\n祝你故障排除愉快!\n","description":"故障排除是一项可以在任何领域学习和应用的技能。通过系统地方法,保持耐心,关注细节,你可以更有效地解决问题,无论系统有多复杂。记住,故障排除不仅仅是修复问题,也是理解系统的机会。"},{"title":"使用tg-bot管理vps","url":"https://qixin.ch/posts/vps-manage/","body":"依赖的包\npython3 -m venv venv\nsource venv/bin/activate\npip3 install python-telegram-bot\n\n# bot.py\nimport subprocess\nimport logging\nimport os\nfrom telegram import Update, BotCommand, InlineKeyboardButton, InlineKeyboardMarkup\nfrom telegram.ext import ApplicationBuilder, CommandHandler, ContextTypes, CallbackQueryHandler\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\n# ===== 配置区 =====\n# 建议通过环境变量传入,避免 Token 硬编码泄露:\n# export BOT_TOKEN="your_token"\n# export ALLOWED_USERS="123456789,1111111"\nBOT_TOKEN = os.environ.get("BOT_TOKEN", "在这里填入Token或通过环境变量传入")\nALLOWED_USERS = set(\n int(uid) for uid in os.environ.get("ALLOWED_USERS", "5469383389").split(",")\n)\n\n# 指令 -> (脚本路径, 菜单描述)\nCOMMANDS = {\n "update_blog": ("/opt/app/tg-bot/scripts/update_blog.sh", "更新博客"),\n "docker": ("/root/scripts/docker_manage.sh", "Docker 管理"),\n # 继续添加: "cmd_name": ("/path/to/script.sh", "描述"),\n}\n# ==================\n\nlogging.basicConfig(\n level=logging.INFO,\n format="%(asctime)s [%(levelname)s] %(message)s",\n)\nlogger = logging.getLogger(__name__)\n\n\ndef is_allowed(user_id: int) -> bool:\n return user_id in ALLOWED_USERS\n\n# ===== 工具函数 =====\n\ndef get_containers(status: str = "running") -> list[str]:\n """获取容器列表,status: running / all"""\n args = ["docker", "ps", "--format", "{{.Names}}"]\n if status == "all":\n args.append("-a")\n result = subprocess.run(args, capture_output=True, text=True)\n containers = result.stdout.strip().split("\\n")\n return [c for c in containers if c]\n\n\ndef run_docker_cmd(args: list[str]) -> tuple[bool, str]:\n """执行 docker 命令,返回 (成功, 输出)"""\n result = subprocess.run(\n ["docker"] + args,\n capture_output=True, text=True, timeout=30\n )\n output = result.stdout.strip() or result.stderr.strip()\n return result.returncode == 0, output\n\n\ndef make_keyboard(buttons: list[tuple[str, str]], cols: int = 1) -> InlineKeyboardMarkup:\n """\n 构建内联键盘\n buttons: [(显示文字, callback_data), ...]\n cols: 每行几个按钮\n """\n kb = []\n row = []\n for label, data in buttons:\n row.append(InlineKeyboardButton(label, callback_data=data))\n if len(row) == cols:\n kb.append(row)\n row = []\n if row:\n kb.append(row)\n kb.append([InlineKeyboardButton("🔙 返回主菜单", callback_data="docker:main")])\n return InlineKeyboardMarkup(kb)\n\n\n# ===== 一级菜单:Docker 主菜单 =====\n\nasync def docker_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE):\n if not is_allowed(update.effective_user.id):\n await update.message.reply_text("⛔ 无权限")\n return\n await update.message.reply_text(\n "🐳 Docker 管理",\n reply_markup=docker_main_menu()\n )\n\n\ndef docker_main_menu() -> InlineKeyboardMarkup:\n buttons = [\n ("⬆️ 升级容器", "docker:pull"),\n ("🔄 重启容器", "docker:restart"),\n ("⏹ 停止容器", "docker:stop"),\n ("▶️ 启动容器", "docker:start"),\n ("📋 查看日志", "docker:logs"),\n ("📊 容器状态", "docker:status"),\n ]\n kb = [[InlineKeyboardButton(label, callback_data=data)] for label, data in buttons]\n kb.append([InlineKeyboardButton("❌ 取消", callback_data="docker:cancel")])\n return InlineKeyboardMarkup(kb)\n\n\n# ===== 二级菜单:选择容器 =====\n\nACTION_CONFIG = {\n "pull": {"label": "升级", "emoji": "⬆️", "status": "running"},\n "restart": {"label": "重启", "emoji": "🔄", "status": "running"},\n "stop": {"label": "停止", "emoji": "⏹", "status": "running"},\n "start": {"label": "启动", "emoji": "▶️", "status": "all"}, # 启动显示所有容器\n "logs": {"label": "查看日志","emoji": "📋", "status": "running"},\n "status": {"label": "查看状态","emoji": "📊", "status": "all"},\n}\n\n\nasync def show_container_list(query, action: str):\n """展示容器列表作为二级菜单"""\n cfg = ACTION_CONFIG[action]\n containers = get_containers(cfg["status"])\n\n if not containers:\n await query.edit_message_text("没有可用的容器")\n return\n\n buttons = [\n (name, f"docker:{action}:{name}")\n for name in containers\n ]\n await query.edit_message_text(\n f"{cfg['emoji']} 选择要{cfg['label']}的容器:",\n reply_markup=make_keyboard(buttons)\n )\n\n\n# ===== 三级操作:执行具体命令 =====\n\nasync def execute_action(query, action: str, container: str):\n """执行具体 docker 操作"""\n cfg = ACTION_CONFIG[action]\n await query.edit_message_text(f"⏳ 正在{cfg['label']} {container}...")\n\n if action == "pull":\n # 获取镜像名\n ok, image = run_docker_cmd([\n "inspect", "--format", "{{.Config.Image}}", container\n ])\n if not ok:\n await query.edit_message_text(f"❌ 获取镜像信息失败\\n```\\n{image}\\n```", parse_mode="Markdown")\n return\n\n image = image.strip()\n await query.edit_message_text(f"⏳ 正在拉取 {image}...")\n\n ok, output = run_docker_cmd(["pull", image])\n if ok:\n await query.edit_message_text(\n f"✅ 镜像 {image} 已更新\\n请手动重启容器以生效。",\n reply_markup=make_keyboard([\n (f"🔄 立即重启 {container}", f"docker:restart:{container}")\n ])\n )\n else:\n await query.edit_message_text(f"❌ 拉取失败\\n```\\n{output}\\n```", parse_mode="Markdown")\n return\n if action == "logs":\n ok, output = run_docker_cmd(["logs", "--tail", "50", container])\n output = output[-3000:] if len(output) > 3000 else output\n status = "📋 最近 50 行日志"\n await query.edit_message_text(f"{status} — {container}\\n```\\n{output or '(无日志)'}\\n```", parse_mode="Markdown")\n return\n\n if action == "status":\n ok, output = run_docker_cmd(["inspect", "--format",\n "状态: {{.State.Status}}\\nIP: {{.NetworkSettings.IPAddress}}\\n启动时间: {{.State.StartedAt}}",\n container])\n await query.edit_message_text(f"📊 {container}\\n```\\n{output}\\n```", parse_mode="Markdown")\n return\n\n # restart / stop / start\n docker_args = {\n "pull": ["pull", container],\n "restart": ["restart", container],\n "stop": ["stop", container],\n "start": ["start", container],\n }\n ok, output = run_docker_cmd(docker_args[action])\n\n if ok:\n await query.edit_message_text(\n f"✅ {container} {cfg['label']}成功",\n reply_markup=InlineKeyboardMarkup([[\n InlineKeyboardButton("🔙 返回主菜单", callback_data="docker:main"),\n InlineKeyboardButton("❌ 取消", callback_data="docker:cancel")\n ]])\n )\n else:\n await query.edit_message_text(f"❌ {cfg['label']}失败\\n```\\n{output}\\n```", parse_mode="Markdown")\n\n\n# ===== 统一回调路由 =====\n\nasync def docker_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):\n query = update.callback_query\n await query.answer()\n\n if not is_allowed(query.from_user.id):\n await query.edit_message_text("⛔ 无权限")\n return\n\n parts = query.data.split(":") # docker:action 或 docker:action:container\n\n match parts:\n case ["docker", "main"]:\n await query.edit_message_text("🐳 Docker 管理", reply_markup=docker_main_menu())\n\n case ["docker", "cancel"]:\n await query.edit_message_text("已取消")\n\n case ["docker", action] if action in ACTION_CONFIG:\n # 二级菜单:展示容器列表\n await show_container_list(query, action)\n\n case ["docker", action, container] if action in ACTION_CONFIG:\n # 三级操作:执行命令\n await execute_action(query, action, container)\n\n case _:\n await query.edit_message_text("❓ 未知操作")\n\n\n\nasync def set_commands(app):\n """Bot 启动时向 Telegram 注册命令菜单"""\n commands = [\n ]\n for cmd, (_, desc) in COMMANDS.items():\n commands.append(BotCommand(cmd, desc))\n await app.bot.set_my_commands(commands)\n logger.info("命令菜单注册成功,共 %d 条", len(commands))\n\n\nasync def run_script(update: Update, context: ContextTypes.DEFAULT_TYPE, script_path: str):\n user = update.effective_user\n if not is_allowed(user.id):\n await update.message.reply_text("⛔ 无权限")\n logger.warning("未授权访问 user_id=%s username=%s", user.id, user.username)\n return\n\n # 检查脚本是否存在\n if not os.path.isfile(script_path):\n await update.message.reply_text(f"❌ 脚本不存在:`{script_path}`", parse_mode="Markdown")\n logger.error("脚本不存在: %s", script_path)\n return\n\n logger.info("执行脚本 user_id=%s script=%s", user.id, script_path)\n await update.message.reply_text("⏳ 执行中...")\n\n try:\n result = subprocess.run(\n ["bash", script_path],\n capture_output=True,\n text=True,\n timeout=60,\n )\n stdout = result.stdout.strip()\n stderr = result.stderr.strip()\n\n if result.returncode == 0:\n output = stdout or "(无输出)"\n status = "✅ 执行成功"\n else:\n output = stderr or stdout or "(无输出)"\n status = f"⚠️ 退出码 {result.returncode}"\n\n # Telegram 消息最长 4096 字符,代码块占 8 字符,留余量\n if len(output) > 3800:\n output = output[:3800] + "\\n...(输出已截断)"\n\n await update.message.reply_text(\n f"{status}\\n```\\n{output}\\n```",\n parse_mode="Markdown",\n )\n\n except subprocess.TimeoutExpired:\n await update.message.reply_text("⚠️ 执行超时(超过 60 秒)")\n logger.warning("脚本超时: %s", script_path)\n except Exception as e:\n await update.message.reply_text(f"❌ 异常: {e}")\n logger.exception("脚本执行异常: %s", script_path)\n\n\n\n\ndef main():\n app = ApplicationBuilder().token(BOT_TOKEN).build()\n\n app.add_handler(CommandHandler("docker", docker_cmd))\n app.add_handler(CallbackQueryHandler(docker_callback, pattern="^docker:"))\n\n # 从 COMMANDS 动态注册,与菜单保持同步\n for cmd, (script, _) in COMMANDS.items():\n def make_handler(s):\n async def handler(update, context):\n await run_script(update, context, s)\n return handler\n app.add_handler(CommandHandler(cmd, make_handler(script)))\n\n # Bot 启动后自动注册菜单\n app.post_init = set_commands\n\n logger.info("Bot 启动中...")\n app.run_polling()\n\n\nif __name__ == "__main__":\n main()\n\n\n","description":"将常用的操作通过tg-bot管理,包括docker的重启、停止、日志等"},{"title":"IX(互联网交换中心)科普:从原理到应用","url":"https://qixin.ch/posts/ix/","body":"什么是 IX?\nIX 即 互联网交换中心(Internet Exchange),是一个用于不同 ASN(自治系统号)之间交换流量的基础设施平台。这一概念在国外已经发展多年,核心目的是让不同网络运营商之间能够直接互联,而无需通过第三方中转。\n\nIX 的工作原理\n以腾讯云香港为例,测试到 DMIT 香港和香港大学两个网络时,路由路径分别经过了:\n\n\n\nEquinix IX(EIE) —— 全球大型数据中心 Equinix 提供的互联网交换平台\nHKIX —— 香港互联网交换中心\n\n这说明腾讯云香港到这两个网络之间,分别通过 EIE 和 HKIX 进行互联。只要双方都接入了 IX 并建立了 BGP Peering,流量通常会优先通过 IX 交换。\n\n接入 IX 有什么好处?\n如果不接入 IX,同时也没有建立私有互联(PNI),不同网络之间就只能通过 T1 运营商的 IP Transit 传输数据。公网传输费用远高于 IX 之间的费用,因此通过 IX 可以大大降低带宽成本。\n\n为什么 IX 在中国也火起来了?\n中国近年来也建设了几个 IX,比较知名的包括:\nIX 名称位置\nCNIX(前海 IX)深圳前海\nSHIXP上海\n\n原理与国外一致:不同 ASN 接入后,可以通过 IX 交换流量。但中国网络环境比较特殊——大部分网络由三大运营商垄断,拥有独立 ASN 并进行 BGP 互联的网络非常少,主要集中在阿里、腾讯、华为等大厂。\n例如,从腾讯上海测试到阿里上海,路由追踪显示流量通过 SHIXP 交换。这样做的主要目的还是降低带宽传输费用,因为国内公网带宽价格极高——目前国内运营商 1G 上行带宽的价格大约为 6000 元/月。\n\n\nIX 与\"跨境专线\"的关系\n为什么 CNIX 跟专线联系上了?为什么能跨境?\n原因很简单:跨境传输线路是商家自己购买的。不同商家购买的跨境专线可能完全不同,市面上有很多公司专门做这块业务,运营商也有提供。\n费用结构分析\n跨境传输本身的费用其实并不算很贵,真正贵的是国内的公网传输部分。比如常见的\"深圳电信入口\"\"广州联通入口\",商家需要:\n\n单独购买一台国内服务器\n购买国内运营商带宽\n通过自己的跨境传输线路到香港出口\n\n其中最贵的部分就是国内带宽。\nIX 专线产品的诞生\n为了节省成本,商家想了一个办法:\n\n通过接入 IX,让用户经由阿里、腾讯等大厂的网络接入商家的入口(商家入口也接入了 IX),从而大大节省入口端的传输费用。\n\n这就是目前各种 IX 专线产品的基本原理。\n\n常见问题 FAQ\n1. IX 是不是就等于专线?\n不是。 IX 只是一个互联网交换平台,本身并不提供跨境线路。所谓的\"IX 专线\",本质上还是商家自己购买的跨境线路,只是入口通过 IX 来交换流量。\n2. 接入 IX 就一定更快吗?\n不一定。 IX 只是提供一个互联点,具体速度还取决于:\n\n双方网络质量\n带宽大小\n对方的策略(对方可以进行限速)\n\n3. 为什么有的 IX 线路会突然不通?\n因为 IX 内部的路由策略可能随时调整,或者对方网络不再接受 IX 的流量,这种情况在实际运营中是可能发生的。\n4. 为什么运营商自己不选择接入 IX?\n因为运营商主要靠卖 IP Transit(公网带宽) 赚钱。如果大量流量通过 IX 直接交换,他们的 Transit 收入就会减少,所以一般情况下不会主动接入。\n5. 是不是所有 IX 产品质量都一样?\n不是。 虽然都叫\"IX\",但以下因素完全由商家自己决定:\n差异因素说明\n跨境线路质量不同商家采购的线路不同\n入口带宽带宽大小直接影响体验\n是否超售超售比例影响高峰期表现\n\n因此,不同商家的 IX 产品体验可能差别很大。\n","description":"IX 本质上就是互联网交换中心(Internet Exchange),这个概念在国外已经是发展了很多年了,主要用于不同 ASN 之间交换流量的。"},{"title":"使用hdhive替换cms增强插件中的nullbr","url":"https://qixin.ch/posts/cms-hdhive/","body":"\n这篇记录是把 cms 增强插件里对 /api/nullbr/... 的调用,替换成走 hdhive 的代理服务。核心目的:\n\n由于cms增强插件是闭源的五个直接修改,只能通过拦截后处理来实现\n\n项目地址:KysonGeek/cms_hdhive_proxy\n前置条件\n\n一台能跑 Python 服务的机器(和 cms 后端同机最好)\nCaddy(也可以换成 Nginx/Traefik,本篇用 Caddy 举例)\n已经有可用的 hdhive token\n\n使用步骤\n1) 拉取代码并配置 Token\ngit clone https://github.com/KysonGeek/cms_hdhive_proxy.git\ncd cms_hdhive_proxy\n\ncat > .env <<'EOF'\nHDHIVE_TOKEN=xxx\nEOF\n\n2) 安装依赖并启动服务\npython3 -m venv venv\n./venv/bin/pip install -r requirements.txt\n\nnohup ./venv/bin/python -u main.py > output.log 2>&1 &\n\n确认启动是否正常:\ntail -n 200 output.log\n\n默认监听端口通常是 8900(以项目实际输出为准)。\n3) Caddy 拦截并转发指定接口\n将 cms.xxx.xx 换成你的域名,127.0.0.1:9527 换成原 cms 后端地址。\ncms.xxx.xx {\n @movie_resources {\n method GET\n path_regexp movie_res ^/api/nullbr/(tv|movie)/(\\d+)/resources$\n }\n handle @movie_resources {\n reverse_proxy 127.0.0.1:8900\n }\n\n @movie_115 {\n method GET\n path_regexp movie_115 ^/api/nullbr/(tv|movie)/(\\d+)/115$\n }\n handle @movie_115 {\n reverse_proxy 127.0.0.1:8900\n }\n\n @cloud_add {\n method POST\n path /api/cloud/add_share_down\n }\n handle @cloud_add {\n reverse_proxy 127.0.0.1:8900\n }\n\n handle {\n reverse_proxy 127.0.0.1:9527\n }\n}\n\n重新加载配置:\nsudo systemctl reload caddy\n\n验证方式\n去页面订阅影片时不报错\n注意事项\n\nHDHIVE_TOKEN 视同密钥,避免写入公开仓库/截图/日志平台。\n代理服务建议做成 systemd 服务或容器,避免机器重启后忘记拉起。\n\n","description":"nullbr失联后,使用hdhive替换"},{"title":"长沙 + 张家界清明假期四日游","url":"https://qixin.ch/posts/changsha-zhangjiajie-travel-guide/","body":"🏔️ 长沙+张家界清明假期四日游:全家老小的山水美食之旅\n清明小长假将至,如果你正在计划一场兼顾自然风光与美食文化的家庭旅行,这份长沙+张家界四日游攻略或许能给你带来灵感。本次行程专为5人家庭设计(夫妻+小姨子+岳父岳母),节奏张弛有度,既涵盖网红打卡地,又深度体验了湖南的山水人文。\n📅 行程总览:4天3晚的湘西风韵\n日期主题亮点\n4/2长沙市区美食+文化橘子洲头、岳麓书院、坡子街美食\n4/3张家界国家森林公园百龙天梯、袁家界、杨家界\n4/4天门山+返程长沙世界最长索道、玻璃栈道、天门洞\n4/5长沙休闲游湖南省博物馆、IFS商圈\n\n🌆 Day 1:长沙初体验——舌尖与文化的双重盛宴\n📍 上午:初探星城\n10:00抵达长沙后,建议入住五一广场或太平街附近酒店,这里交通便利,步行可达多个景点。放好行李后稍作休整,便可开启美食之旅。\n🍜 中午:味蕾觉醒\n坡子街和太平街是美食聚集地:\n\n文和友老长沙龙虾馆:复古装修风格,招牌小龙虾不可错过\n黑色经典臭豆腐:外酥里嫩,浇上秘制汤汁\n茶颜悦色:长沙限定奶茶,推荐\"幽兰拿铁\"\n长辈友好选择:向群锅饺或杨裕兴米粉,口味温和不刺激\n\n🏛️ 下午:文化巡礼\n\n橘子洲头(14:00-15:30):乘坐小火车直达毛泽东青年艺术雕塑,清明时节洲上绿意盎然,适合全家合影\n岳麓山/岳麓书院(16:00-17:30):考虑长辈体力,建议游览岳麓书院(门票50元),感受千年学府的文化底蕴。若体力充沛,可乘坐索道(单程30元)上山俯瞰长沙全景。\n\n🌃 晚上:星城夜未央\n\n晚餐推荐费大厨辣椒炒肉或炊烟时代小炒黄牛肉,体验正宗湘菜风味\n饭后沿湘江风光带散步,欣赏夜景\n太平老街夜游,感受长沙夜生活氛围\n\n\n重要提示:当晚需提前预订第二天长沙→张家界的高铁票(建议7:00-7:30班次)和张家界国家森林公园门票(4日票225元/人,含环保车)。\n\n🏞️ Day 2:张家界国家森林公园——大自然的鬼斧神工\n🚄 清晨出发\n\n6:30 酒店退房/寄存行李,前往长沙南站\n7:00-7:30 乘坐高铁,约10:30-11:00抵达张家界西站\n11:00 打车/拼车前往武陵源入口(约50分钟)\n\n🍲 午餐:张家界特色\n武陵源镇上用餐,推荐尝试当地特色三下锅,胡师傅三下锅是不错的选择。\n🥾 下午:核心景区游览\n推荐照顾长辈体力的经典线路:\n武陵源门票站进 → 乘环保车至百龙天梯下站\n→ 百龙天梯上行(72元/人,单程约2分钟,世界最高户外电梯)\n→ 袁家界景区(约2小时)\n ✦ 天下第一桥\n ✦ 哈利路亚山(阿凡达取景地)\n ✦ 迷魂台\n→ 乘环保车至杨家界(约1.5小时)\n ✦ 天然长城\n ✦ 乌龙寨(台阶较多,长辈量力而行)\n→ 乘环保车返回武陵源门票站出\n\n\n体力提醒:袁家界为核心景点,道路相对平坦;杨家界台阶较多,可根据长辈体力灵活调整,实在走不动可省略乌龙寨。\n\n🏨 晚上:武陵源休整\n\n入住武陵源镇区酒店/民宿(建议提前预订,清明节旺季价格会上涨)\n晚餐可尝试岩耳炖鸡、葛根粉等当地特色\n溪布街逛逛夜市,早点休息为第二天行程蓄力\n\n⛰️ Day 3:天门山奇观——挑战云端的震撼\n🌅 上午:天门山精华游\n\n早起退房,打车前往张家界市区天门山索道站(武陵源到市区约1小时车程)\n建议购买A线票(索道上、快线下)或B线票(快线上、索道下),票价275元/人\n\n天门山必体验亮点:\n\n天门山索道:全长7455米,世界最长高山客运索道,30分钟空中之旅\n玻璃栈道:悬崖峭壁上的透明栈道(鞋套5元),考验勇气的绝佳体验\n天门洞:世界最高天然穿山溶洞,999级台阶(可选择乘自动扶梯上下,费用32元/人,非常推荐给长辈)\n鬼谷栈道:悬崖绝壁上的空中走廊,感受惊险与刺激\n\n\n关键提醒:天门洞的999级台阶对长辈有难度,自动扶梯是不错的选择,可以节省体力。\n\n🍴 午餐与返程\n\n12:30 天门山下来后在张家界市区快速用餐\n13:30 乘坐高铁返回长沙(建议选择14:00左右班次,约17:30抵达)\n\n🌃 长沙之夜\n\n入住长沙市区酒店\n晚餐推荐火宫殿(百年老字号,一站式体验长沙小吃)\n饭后可去IFS国金中心看楼顶的KAWS雕塑打卡,顺便逛逛商圈\n\n🏛️ Day 4:长沙文化休闲——历史与现代的碰撞\n🏺 上午:历史文化之旅\n\n湖南省博物馆(9:00-10:30):免费但需提前预约!必看马王堆汉墓出土文物、辛追夫人\n五一广场商圈(10:30-12:00):逛街购物,给亲朋带手信(灯芯糕、酱板鸭等)\n\n🍽️ 中午:地道湘菜告别宴\n\n推荐壹盏灯或笨萝卜浏阳菜馆\n给长辈点几道不太辣的菜:剁椒鱼头(鲜香为主)、小炒河虾\n\n🌿 下午:轻松收官\n方案A(文艺路线):\n\n谢子龙影像艺术馆 → 李自健美术馆(均免费,建筑本身就很出片)\n\n方案B(休闲路线,推荐给长辈):\n\n烈士公园湖边散步 → 找家茶馆喝下午茶\n或去万家丽购物广场逛逛\n\n👋 傍晚:告别长沙\n\n18:00-20:30 告别晚餐,可选择湘里人家或回到坡子街再吃一轮小吃\n再来一杯茶颜悦色收尾\n21:00 收拾行李,前往车站/机场\n23:00 离开长沙\n\n💡 实用信息汇总\n💰 预估费用(5人合计)\n\n长沙⇌张家界高铁(往返):约1,650元(考虑租车,时间自由不需要赶高铁,能省下1000元)\n张家界森林公园门票:1,125元(4日票225元/人,含环保车)\n百龙天梯(单程):360元\n天门山门票(含索道):1,375元\n住宿(3晚):约1,500-2,500元(民宿)\n餐饮(4天):约2,000-3,000元\n市内交通+打车:约500-800元\n合计:约8,500-11,000元\n\n📋 必做清单\n\n提前购买长沙<——>张家界高铁票(清明节热门线路,务必提前抢票)\n提前预约湖南省博物馆(公众号\"湖南省博物院\"预约)\n提前购买张家界国家森林公园门票+天门山门票\n准备舒适的运动鞋(张家界步行量大)\n带好雨具(清明时节长沙和张家界多雨)\n给长辈准备登山杖(景区也可租,约10-20元)\n随身带防晒霜+薄外套(山上温差大,4月张家界山顶约10-15℃)\n\n🍽️ 饮食注意\n\n湘菜偏辣,点菜时可跟服务员说\"少辣\"或\"微辣\"\n给长辈多点蒸菜类(如剁椒鱼头、蒸腊味),相对不那么辣\n张家界景区内食物贵且品质一般,建议自带干粮零食上山\n\n","description":"看看著名的橘子洲头,体验一下玻璃栈桥,天门洞"},{"title":"【NodeQuality】riven","url":"https://qixin.ch/nq/riven/","body":"💻基本信息\n\n🎬IP质量\n\n🌐网络质量\n\n📍回程路由\n\nNodeQuality链接\n","description":"极致的电信、联通日本服务器"},{"title":"【NodeQuality】dc9","url":"https://qixin.ch/nq/dc9/","body":"💻基本信息\nBasic System Information:\n---------------------------------\nUptime : 0 days, 5 hours, 29 minutes\nProcessor : AMD EPYC-Genoa Processor\nCPU cores : 2 @ 2445.404 MHz\nAES-NI : ✔ Enabled\nVM-x/AMD-V : ❌ Disabled\nRAM : 2.0 GiB\nSwap : 1024.0 MiB\nDisk : 40.0 GiB\nDistro : Debian GNU/Linux 12 (bookworm)\nKernel : 6.1.0-38-amd64\nVM Type : KVM\nIPv4/IPv6 : ✔ Online / ❌ Offline\n\nIPv4 Network Information:\n---------------------------------\nISP : IT7 Networks Inc\nASN : AS25820 IT7 Networks Inc\nHost : IT7 Networks Inc\nLocation : Los Angeles, California (CA)\nCountry : United States\n\nfio Disk Speed Tests (Mixed R/W 50/50) (Partition -):\n---------------------------------\nBlock Size | 4k (IOPS) | 64k (IOPS)\n ------ | --- ---- | ---- ---- \nRead | 294.11 MB/s (73.5k) | 3.74 GB/s (58.5k)\nWrite | 294.89 MB/s (73.7k) | 3.76 GB/s (58.8k)\nTotal | 589.00 MB/s (147.2k) | 7.51 GB/s (117.4k)\n | | \nBlock Size | 512k (IOPS) | 1m (IOPS)\n ------ | --- ---- | ---- ---- \nRead | 6.19 GB/s (12.0k) | 6.48 GB/s (6.3k)\nWrite | 6.51 GB/s (12.7k) | 6.91 GB/s (6.7k)\nTotal | 12.71 GB/s (24.8k) | 13.40 GB/s (13.0k)\n\nGeekbench 5 Benchmark Test:\n---------------------------------\nTest | Value \n | \nSingle Core | 1116 \nMulti Core | 2177 \nFull Test | https://browser.geekbench.com/v5/cpu/23739802\n\n SysBench CPU 测试 (Fast Mode, 1-Pass @ 5sec)\n---------------------------------\n 1 线程测试(单核)得分: 3651 Scores\n 2 线程测试(多核)得分: 7251 Scores\n SysBench 内存测试 (Fast Mode, 1-Pass @ 5sec)\n---------------------------------\n 单线程读测试: 41915.78 MB/s\n 单线程写测试: 26302.73 MB/s\n\n🎬IP质量\n\n🌐网络质量\n\n📍回程路由\n\nNodeQuality链接\n","description":""},{"title":"【NodeQuality】gen2","url":"https://qixin.ch/nq/gen2/","body":"💻基本信息\nBasic System Information:\n---------------------------------\nUptime : 0 days, 0 hours, 17 minutes\nProcessor : AMD EPYC 7763 64-Core Processor\nCPU cores : 2 @ 2445.406 MHz\nAES-NI : ✔ Enabled\nVM-x/AMD-V : ✔ Enabled\nRAM : 3.8 GiB\nSwap : 256.0 MiB\nDisk : 30.0 GiB\nDistro : Debian GNU/Linux 12 (bookworm)\nKernel : 6.1.0-38-cloud-amd64\nVM Type : STANDARD PC (Q35 + ICH9, 2009)\nIPv4/IPv6 : ✔ Online / ✔ Online\n\nIPv6 Network Information:\n---------------------------------\nISP : xTom Japan Corporation\nASN : AS3258 xTom Japan Corporation\nHost : Customer Route\nLocation : Tokyo, Tokyo (13)\nCountry : Japan\n\nfio Disk Speed Tests (Mixed R/W 50/50) (Partition -):\n---------------------------------\nBlock Size | 4k (IOPS) | 64k (IOPS)\n ------ | --- ---- | ---- ---- \nRead | 447.80 MB/s (111.9k) | 5.90 GB/s (92.3k)\nWrite | 448.98 MB/s (112.2k) | 5.93 GB/s (92.8k)\nTotal | 896.79 MB/s (224.1k) | 11.84 GB/s (185.1k)\n | | \nBlock Size | 512k (IOPS) | 1m (IOPS)\n ------ | --- ---- | ---- ---- \nRead | 8.84 GB/s (17.2k) | 8.71 GB/s (8.5k)\nWrite | 9.31 GB/s (18.1k) | 9.29 GB/s (9.0k)\nTotal | 18.15 GB/s (35.4k) | 18.00 GB/s (17.5k)\n\nGeekbench 5 Benchmark Test:\n---------------------------------\nTest | Value \n | \nSingle Core | 1195 \nMulti Core | 2343 \nFull Test | https://browser.geekbench.com/v5/cpu/23767254\n\n SysBench CPU 测试 (Fast Mode, 1-Pass @ 5sec)\n---------------------------------\n 1 线程测试(单核)得分: 3630 Scores\n 2 线程测试(多核)得分: 7273 Scores\n SysBench 内存测试 (Fast Mode, 1-Pass @ 5sec)\n---------------------------------\n 单线程读测试: 45369.33 MB/s\n 单线程写测试: 26003.55 MB/s\n\n🎬IP质量\n\n🌐网络质量\n\n📍回程路由\n\nNodeQuality链接\n","description":"极致的电信、联通日本服务器"},{"title":"【NodeQuality】瓦工hk85","url":"https://qixin.ch/nq/hk85/","body":"💻基本信息\nBasic System Information:\n---------------------------------\nUptime : 0 days, 0 hours, 48 minutes\nProcessor : Intel Xeon Processor (Cascadelake)\nCPU cores : 2 @ 2699.990 MHz\nAES-NI : ✔ Enabled\nVM-x/AMD-V : ❌ Disabled\nRAM : 2.0 GiB\nSwap : 1024.0 MiB\nDisk : 40.0 GiB\nDistro : Debian GNU/Linux 12 (bookworm)\nKernel : 6.1.0-9-amd64\nVM Type : KVM\nIPv4/IPv6 : ✔ Online / ❌ Offline\n\nIPv4 Network Information:\n---------------------------------\nISP : IT7 Networks Inc\nASN : AS25820 IT7 Networks Inc\nHost : IT7 Networks Inc\nLocation : Hong Kong, Kowloon ()\nCountry : Hong Kong\n\nfio Disk Speed Tests (Mixed R/W 50/50) (Partition -):\n---------------------------------\nBlock Size | 4k (IOPS) | 64k (IOPS)\n ------ | --- ---- | ---- ---- \nRead | 25.30 MB/s (6.3k) | 255.70 MB/s (3.9k)\nWrite | 25.33 MB/s (6.3k) | 257.04 MB/s (4.0k)\nTotal | 50.63 MB/s (12.6k) | 512.75 MB/s (8.0k)\n | | \nBlock Size | 512k (IOPS) | 1m (IOPS)\n ------ | --- ---- | ---- ---- \nRead | 637.80 MB/s (1.2k) | 778.20 MB/s (759)\nWrite | 671.69 MB/s (1.3k) | 830.03 MB/s (810)\nTotal | 1.30 GB/s (2.5k) | 1.60 GB/s (1.5k)\n\nGeekbench 5 Benchmark Test:\n---------------------------------\nTest | Value \n | \nSingle Core | 585 \nMulti Core | 1133 \nFull Test | https://browser.geekbench.com/v5/cpu/23686312\n\n SysBench CPU 测试 (Fast Mode, 1-Pass @ 5sec)\n---------------------------------\n 1 线程测试(单核)得分: 749 Scores\n 2 线程测试(多核)得分: 1451 Scores\n SysBench 内存测试 (Fast Mode, 1-Pass @ 5sec)\n---------------------------------\n 单线程读测试: 15184.67 MB/s\n 单线程写测试: 13769.07 MB/s\n\n🎬IP质量\n\n🌐网络质量\n\n📍回程路由\n\nNodeQuality链接\n","description":""}]