\\\\n\\";\\n} else {\\n // 假设远程服务期望接收纯文本,我们直接发送输出\\n fwrite($socket, $output);\\n\\n // 你可以在这里添加额外的逻辑来读取远程服务的响应(如果需要)\\n // ...\\n\\n // 关闭连接\\n fclose($socket);\\n echo \\"输出已发送到远程服务器\\";\\n}\\n
\\n 本作品采用《CC 协议》,转载必须注明作者和本文链接\\n\\n\\n \\n
每天晒白牙 每天晒白牙 2024-04-09 00:00 北京
\\n今天是白牙入职腾讯三周年的日子,时间过得好快,两周年的文章好像刚写完一样《入职腾讯两周年的收获与感受》,入职腾讯前的纠结也历历在目《北漂7年程序猿回看工作选择》,简单分享下这一年,白牙都学到了什么。
\\n0**1**
\\n认知提升
\\n1.成长是件很私人的事,成长是你自己的事,你需要100%负责。
\\n2.工作要主动,从“凭什么要我做?”,到“愿意主动去多做事儿”,再到“把奋斗当做习惯”。越主动的人收获越多。在工作中主动找一些需求外的事做,比如做一个提效工具。在日常繁忙的工作中,你需要偶尔抬头,想想哪些问题困扰着你,也许这就是一个工具的出发点。
\\n3.让你的上级知道你的价值,让他的上级知道就更好了。你要有这种意识,不能陷入不断解决眼前问题中不能自拔,要主动挖掘出潜在的价值点。
\\n\\n\\n你到底是在解决问题,还是在寻找机会?
\\n– 彼得·德鲁克《成果管理》
\\n
\\n\\n成果的取得靠主动挖掘机会,而不能仅靠解决眼前的问题
\\n– 少楠
\\n
4.公司不为你的忙碌买单,公司只为你提供的价值买单。你的领导并不关心你做了多少件事,他关心的是,问题有没有真正解决。所以没必要卷加班。
\\n5.跟对人,真的很重要,在组织架构调整时,愈发明显。
\\n6.不要只当工具人,要时刻想着业务,开发也要主动思考并参与为业务赋能上,提供建议,不要只当做需求的工具人,时刻牢记「降本增效,提质创收」。
\\n7.每个团队、每个业务都有它存在的价值,你觉得你做的业务没价值,可能别的团队做的还不如你现在做的。
\\n8.不要指望提醒用户按照你要求的做,用户就会照做,一定要在产品层面加限制,功能限制的作用远远大于提醒。
\\n9.一份工作不能只盯着工资,更要关注长远利益,比如个人经验的积累、个人成长、Work Life Balance 等。总之,你应该有个干现在工作的理由,如果现在已经找不到了,可能就要考虑换个工作了。
\\n10.一定要保证自己手头有活儿可做,这才可能保证你不下牌桌。99%的成功只是在场而已。在此基础上,也要会挑活儿,挑有价值的活儿,挑能讲新故事的活儿。
\\n挑活不是你想做啥就做啥,不想做啥就不做。你要把手头的活做好,让领导发现你有能力去做更有挑战的事,让他相信你的能力,后面会主动给你分配那些有挑战、有价值的活.
\\n你也可以主动申请参与到那个有价值的活里,保持在场就行,做这种活儿,对你绩效、晋升都是加分项,因为领导也会拿这些事去讲故事。
\\n11.大环境真的不好,找工作真的不容易,要猥琐发育,千万别浪。
\\n12.别再问做管理还是做技术了?不管做啥技术都不能丢,这是你吃饭的工具。即使做到了管理,甚至做了多年的管理,也可能有下来的那天,下来不会写代码怎么办?职场真的没有稳定一说。
\\n13.充分利用职场资源,主动抓机会向合作的同事学习,比如排查问题时,可能会遇到DBA、运维等,可以趁机往深里多问几个问题
\\n14.在业务工程团队,如果你还能做数据,你的壁垒就稍微高些,工程谁都能写,但数据就不一定了。如果你还会算法或大模型LLM相关的应用开发,就更好了。
\\n0**2**
\\n晋升&绩效
\\n15.晋升或绩效考核的衡量标准如果不明确,与上级的人情关系很重要,所以一定要关注与上级的人情关系,最好别抱有“老子技术好,此处不留爷自有留爷处”的心态,前几年可能还行,现在可别。
\\n16.绩效、晋升都是人打的,人打的就不乏主观,于你而言,就会出现你认为的“不公平”,但要明白,即使结果不如意,并不一定代表你这个人不行。不要过度依赖职场的绩效和晋升这个单一的评价体系,一定要构建对自己多维度的评价体系,这个需要自己去探索和挖掘,这样才不会因为绩效不好、晋升不过而郁郁寡欢,值得你用心做的事有很多,职场只是其一。
\\n\\n17.晋升与绩效的名额有限,大部分员工体验不到这些激励。
\\n18.晋升三大原则:
\\n\\n\\n主动原则:主动做事的人比等着安排工作的人更容易晋升。
\\n成长原则:一边做事一边挖掘成长点、提升自己能力的人,比光顾着做事的人更容易晋升。
\\n价值原则:有能力为公司产出价值的人,比空有一身能力的人更容易晋升。
\\n– 李运华 《大厂晋升指南》
\\n
19.晋升答辩是做证明题,证明你已经达到了下一个职级的要求,晋升答辩不是做技术分享,思考的过程可能比你最后选的方案更重要。平时要多积累,有的人提前一年就开始准备。
\\n0**3**
\\n薪资
\\n20.公司不会为员工的成长涨工资,只会为成长后做得更好、产出更多的人涨工资。
\\n21.工作是一个人把最多的清醒时间都投入的事情,只想着赚了多少工资并不明智,聪明人一定要收获更多。
\\n22.大环境不好的情况下外部激励减少,比如调薪的名额骤减,你要找到内部驱动,关注成长、成事,或者一些xx感
\\n23.涨薪慢、不涨薪可能才是真正的常态,只是前几年互联网红利,让人误以为每年涨薪才是常态。但有机会也要自己争取。
\\n0**4**
\\n向上管理
\\n24.向上管理是一种有自主意识的方法,通过与你的老板在目标上达成共识,并最终用这个目标满足你、你的老板、你的组织的最大利益。
\\n25.向上管理与你的老板无关,老板都没得选的,向上管理不是你老板的责任,是你自己的责任。
\\n26.向上管理是一种能力、意愿、行为习惯。你知道它对,发自内心的认可,同时要培养自己有能力去跟老板沟通,和他同频。另外也要会和他谈判,不要怕,主动去聊,老板换的这么快,你怕啥呢?
\\n27.向上管理的目的是帮助组织成功,让老板成功,给老板创造价值,给自己创造价值,让自己成功。
\\n升级加薪聊绩效过程中,如果我觉得自己受到了老板“不公正”的对待,该如何“怼”回去?
\\n28.有问题及时找领导反馈与沟通,让领导知道事情的进展以及是否有问题需要他帮忙,别一个人憋着。
\\n29.别老盯着领导的缺点,尝试关注下领导的优点,并借用领导的优势为自己助力。
\\n0**5**
\\n职场中如何保护好自己?
\\n30.要敢于说不
\\n如果团队分工是按模块划分,临时分给你其他模块的需求,尤其是复杂恶心需求时,要敢于说不。
\\n31.让自己手头永远有需求,最好至少2个,这样有拒绝的理由。
\\n32.拒绝时可以直接,可以委婉,比如手头的需求比较紧急,暂时抽不开身,再加上对这块不太熟悉,担心出问题影响不好,如果非得需要我来支持,我需要xxx,这里可以申请一些资源。
\\n33.方案一定要讨论清楚
\\n尤其是开发不熟悉的业务时,如果想当然得开发,大概率会出问题。
\\n34.做好充分的自测并要求测试同学做好测试
\\n免测这种费力不讨好的事,做好了没有表扬,做砸了还可能背锅,要学会保护自己,除非你非常想做那块业务。
\\n0**6**
\\n结尾
\\n最后以脱不花的「五点工作交流法:交代工作和接收任务时要关注的 5 个关键点」收尾
\\n1. 起点:上下文,为什么要做这件事?
\\n2. 终点:目标是什么,达到什么标准?
\\n3. 重点:关键点在哪里?
\\n4. 卡点:可能面临的风险和坑在哪里?
\\n5. 节点:多久同步,里程碑节点的交付物是什么?
\\n\\n \\n\\n 本作品采用《CC 协议》,转载必须注明作者和本文链接\\n\\n\\n \\n
起点:上下文,为什么要做这件事?
\\n终点:目标是什么,达到什么标准?
\\n重点:关键点在哪里?
\\n卡点:可能面临的风险和坑在哪里?
\\n节点:多久同步,里程碑节点的交付物是什么?
\\nRESP是github上一款免费的Redis图形化管理软件
\\n下载地址:github.com/lework/RedisDesktopMana...
\\n1、直接点击下载和解压安装就可以了
\\n连接之前确保redis已经启动
Redis提供了一个可执行文件 redis-server 用于启动 Redis 服务器。要启动 Redis,你可以在终端中输入以下命令:
redis-server
1
默认情况下,这将使用默认配置文件(redis.conf)启动 Redis 服务器。
如果你想使用不同的配置文件来启动 Redis,可以通过在命令后面指定配置文件路径来实现,例如:
\\nredis-server /path/to/redis.conf
1
请确保在启动 Redis 之前已正确安装并配置好 Redis。
2、打开软件,点击“连接到redis服务器”
\\n直接点击“连接设置”
\\n在连接设置中填写:
名字(随便写)
地址:Linux 系统的 IP 地址(可以通过 ip addr查看)
密码(可选):如果在redis的配置文件中配置了密码,则需要填写
用户(可选):默认不填写
填写完成后,点击“测试连接”:如果连接不成功,可以进行试一下,下一步配置
\\n连接不成功:尝试在linux中执行下面的两个命令:
以下命令是用于配置 Linux 防火墙(firewalld)以开放指定的端口 (6379/tcp)。
1、
firewall-cmd –zone=public –add-port=6379/tcp –permanent
1
这个命令添加一个规则到 “public” 区域(zone)的防火墙配置中,允许通过端口 6379 的 TCP 连接。–permanent 参数表示该规则将被永久保存,重新启动后仍然有效。
2、
\\nfirewall-cmd –reload
1
这个命令重新加载防火墙规则,使最新的修改生效。当你添加、删除或修改防火墙规则时,都需要执行这个命令才能使更改生效。
注意事项:
\\n以上命令需要以管理员权限(例如 root 用户或者使用 sudo)来执行。
1、在执行前,请确保已经安装了 firewalld,并且正在运行。
2、6379 是 Redis 默认的端口号,如果你在使用其他端口,则需要相应地修改上述命令中的端口号。
\\n 本作品采用《CC 协议》,转载必须注明作者和本文链接\\n\\n\\n \\n
我推荐一个吧 Tiny RDM \\ngithub.com/tiny-craft/tiny-rdm
\\n这个感觉更好用\\ngithub.com/qishibo/AnotherRedisDes...
\\n我就是从Another Redis Desktop Manager换成 Tiny RDM的
\\n你这个不带ssh连接的,我之前付费买了一个带ssh连接的, resp现在不更新了
\\n都知道,小编前面已经简单介绍过在 windows 下 hadoop 和 hive 环境搭建和基本使用。这次的 Spark 有点突兀,但是也可以先忽略,重要的是先在 IDEA 中安装 bigData 插件连接 hadoop 已经 HDFS,而后再简单介绍使用 Spark 操作 Hive。
\\n1. 点击 File, 选择 Settings,再选择 Plugins 搜索 Big Data Tools,最后下载安装。
\\n2. 下载完毕后,底部和右侧栏会多出 Hadoop 或 Big Data Tools 的选项。
\\n1. 进入 hadoop 的 sbin 目录,start-all 启动成功,打开 web 控制台 127.0.0.1:50070 (默认),记住如下标志的节点地址,后面 hdfs 连接的就是这个。
\\n2. 只要 hadoop 启动成功后,打开 IDEA 的 hadoop 其实就可以正常自动连接了。
\\n3. 或者打开右侧栏的 Big Data Tools,添加一个连接,Hadoop。
\\n4. 连接 Hdfs。
\\n(1). 点击右侧栏 Big Data Tools 新增 Hdfs。
\\n(2). 重要的就是 Authentication type,选择 Explicit uri。File system URI 填写的就是上面控制台的节点地址。
\\n(3). 连接成功后就可以清晰的看到 HDFS 的目录,并且可以创建,删除和上传。不过需要对指定路径授权。
\\n关于操作 Hive, 以下基于 Maven 构建 Scala 项目。项目创建和 Hive 就略过了,好像在 Kafka 一文中介绍过如何新建 Maven 的 Scala,而 Hive 的产品还是原理介绍网上比较多,以下主要是小编的日志式记录,所以以过程居多,那么就开始了。
\\n1. pom.xml 添加如下依赖并安装 (其实是我整个文件,不需要的可以根据注释删除)。
\\n<project xmlns=\\"http://maven.apache.org/POM/4.0.0\\" xmlns:xsi=\\"http://www.w3.org/2001/XMLSchema-instance\\" xsi:schemaLocation=\\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\\">\\n <modelVersion>4.0.0</modelVersion>\\n <groupId>org.example</groupId>\\n <artifactId>maven_scala_test</artifactId>\\n <version>1.0-SNAPSHOT</version>\\n <name>${project.artifactId}</name>\\n <description>My wonderfull scala app</description>\\n <inceptionYear>2015</inceptionYear>\\n <licenses>\\n <license>\\n <name>My License</name>\\n <url>http://....</url>\\n <distribution>repo</distribution>\\n </license>\\n </licenses>\\n\\n <properties>\\n <maven.compiler.source>1.6</maven.compiler.source>\\n <maven.compiler.target>1.6</maven.compiler.target>\\n <encoding>UTF-8</encoding>\\n <scala.version>2.11.5</scala.version>\\n <scala.compat.version>2.11</scala.compat.version>\\n <spark.version>2.2.0</spark.version>\\n <hadoop.version>2.6.0</hadoop.version>\\n <hbase.version>1.2.0</hbase.version>\\n </properties>\\n\\n <dependencies>\\n <dependency>\\n <groupId>org.scala-lang</groupId>\\n <artifactId>scala-library</artifactId>\\n <version>${scala.version}</version>\\n </dependency>\\n\\n <!-- Test -->\\n <dependency>\\n <groupId>junit</groupId>\\n <artifactId>junit</artifactId>\\n <version>4.11</version>\\n<!-- <scope>test</scope>-->\\n </dependency>\\n <dependency>\\n <groupId>org.specs2</groupId>\\n <artifactId>specs2-core_${scala.compat.version}</artifactId>\\n <version>2.4.16</version>\\n<!-- <scope>test</scope>-->\\n </dependency>\\n <dependency>\\n <groupId>org.scalatest</groupId>\\n <artifactId>scalatest_${scala.compat.version}</artifactId>\\n <version>2.2.4</version>\\n<!-- <scope>test</scope>-->\\n </dependency>\\n\\n <!--scala-->\\n <dependency>\\n <groupId>org.scala-lang</groupId>\\n <artifactId>scala-library</artifactId>\\n <version>${scala.version}</version>\\n </dependency>\\n\\n <!-- spark -->\\n <dependency>\\n <groupId>org.apache.spark</groupId>\\n <artifactId>spark-core_2.11</artifactId>\\n <version>${spark.version}</version>\\n </dependency>\\n <dependency>\\n <groupId>org.apache.spark</groupId>\\n <artifactId>spark-sql_2.11</artifactId>\\n <version>${spark.version}</version>\\n </dependency>\\n <dependency>\\n <groupId>org.apache.spark</groupId>\\n <artifactId>spark-streaming_2.11</artifactId>\\n <version>${spark.version}</version>\\n <scope>provided</scope>\\n </dependency>\\n <dependency>\\n <groupId>org.apache.spark</groupId>\\n <artifactId>spark-mllib_2.11</artifactId>\\n <version>${spark.version}</version>\\n <scope>provided</scope>\\n </dependency>\\n <dependency>\\n <groupId>org.apache.spark</groupId>\\n <artifactId>spark-hive_2.11</artifactId>\\n <version>${spark.version}</version>\\n <!--<scope>provided</scope>-->\\n </dependency>\\n\\n <!-- hadoop -->\\n <dependency>\\n <groupId>org.apache.hadoop</groupId>\\n <artifactId>hadoop-client</artifactId>\\n <version>${hadoop.version}</version>\\n </dependency>\\n <dependency>\\n <groupId>org.apache.hadoop</groupId>\\n <artifactId>hadoop-common</artifactId>\\n <version>${hadoop.version}</version>\\n </dependency>\\n <dependency>\\n <groupId>org.apache.hadoop</groupId>\\n <artifactId>hadoop-hdfs</artifactId>\\n <version>${hadoop.version}</version>\\n </dependency>\\n\\n <!--hbase-->\\n <dependency>\\n <groupId>org.apache.hbase</groupId>\\n <artifactId>hbase-client</artifactId>\\n <version>${hbase.version}</version>\\n </dependency>\\n <dependency>\\n <groupId>org.apache.hbase</groupId>\\n <artifactId>hbase-server</artifactId>\\n <version>${hbase.version}</version>\\n </dependency>\\n\\n <!--kafka-->\\n <dependency>\\n <groupId>org.apache.kafka</groupId>\\n <artifactId>kafka_2.11</artifactId>\\n <version>1.1.0</version>\\n </dependency>\\n\\n <dependency>\\n <groupId>org.apache.kafka</groupId>\\n <artifactId>kafka-clients</artifactId>\\n <version>1.1.0</version>\\n </dependency>\\n\\n </dependencies>\\n\\n <build>\\n <sourceDirectory>src/main/scala</sourceDirectory>\\n <testSourceDirectory>src/test/scala</testSourceDirectory>\\n <plugins>\\n <plugin>\\n <!-- see http://davidb.github.com/scala-maven-plugin -->\\n <groupId>net.alchim31.maven</groupId>\\n <artifactId>scala-maven-plugin</artifactId>\\n <version>3.2.0</version>\\n <executions>\\n <execution>\\n <goals>\\n <goal>compile</goal>\\n <goal>testCompile</goal>\\n </goals>\\n <configuration>\\n <args>\\n<!-- <arg>-make:transitive</arg>-->\\n <arg>-dependencyfile</arg>\\n <arg>${project.build.directory}/.scala_dependencies</arg>\\n </args>\\n </configuration>\\n </execution>\\n </executions>\\n </plugin>\\n <plugin>\\n <groupId>org.apache.maven.plugins</groupId>\\n <artifactId>maven-surefire-plugin</artifactId>\\n <version>2.18.1</version>\\n <configuration>\\n <useFile>false</useFile>\\n <disableXmlReport>true</disableXmlReport>\\n <!-- If you have classpath issue like NoDefClassError,... -->\\n <!-- useManifestOnlyJar>false</useManifestOnlyJar -->\\n <includes>\\n <include>**/*Test.*</include>\\n <include>**/*Suite.*</include>\\n </includes>\\n </configuration>\\n </plugin>\\n </plugins>\\n </build>\\n</project>\\n
\\n\\n2. 项目的 resources 新建元数据文件,可以是 txt,以空格为列,换行为行,这里对 hive 表格创建时重要。
\\n在通过 HQL 创建表格,如何没有指定分列和分行表示,再通过 HQL 的 select 查询数据都是 NULL,具体可以看下面代码演示。
\\n3. 加载源数据文件,只需要项目根目录以下的路径即可。比如 resouces 下的 hello.txt 只需要指定
\\nsrc/main/resources/hello.txt
\\n4. Hive 相关操作的代码。
\\n这里需要注意的是,hive 中的 Default(默认)数据仓库的最原始位置是在 hdfs 上的 /user/hive/warehouse,也就是以后在默认下,新建的表都在那个目录下。
\\n而仓库的原始位置是本地的 /usr/local/hive/conf/hive-default.xml.template 文件里配置
\\npackage com.xudong\\n\\nimport org.apache.spark.sql.SparkSession\\n\\nobject TestSparkHiveHql {\\n\\n def main(args: Array[String]): Unit = {\\n\\n // 创建spark环境\\n val spark = SparkSession\\n .builder()\\n .appName(\\"Spark Hive HQL\\")\\n .master(\\"local[*]\\")\\n .config(\\"spark.sql.warehouse.dir\\",\\"hdfs://rebuildb.xdddsd75.com:9500/user/hive/warehouse\\")\\n .enableHiveSupport()\\n .getOrCreate();\\n\\n import spark.implicits._\\n import spark.sql\\n\\n // 显示HDFS数据库\\n spark.sql(\\"show databases\\").show();\\n // 使用指定数据库\\n spark.sql(\\"use default\\");\\n // 创建表格并约定字段\\n spark.sql(\\"CREATE TABLE users(id int, name string) ROW FORMAT DELIMITED FIELDS TERMINATED BY \' \' LINES TERMINATED BY \'\\\\\\\\n\' STORED AS TEXTFILE\\");\\n // 将本地数据加载到表格\\n spark.sql(\\"LOAD DATA LOCAL INPATH \'src/main/resources/hello.txt\' overwrite into table users\\");\\n\\n // 查询表格数据HQL\\n spark.sql(\\"SELECT * FROM users\\").show()\\n\\n // 聚合统计表格数据条数HQL\\n spark.sql(\\"SELECT COUNT(*) FROM users\\").show()\\n\\n // 多表关联查询\\n spark.sql(\\"select * from info i join users u on u.id = i.user_id\\").show();\\n\\n }\\n\\n}\\n
\\n\\n5. hdfs 简单操作示例。
\\npackage com.xudong\\n\\npackage com.dkl.leanring.spark.hdfs\\nimport java.net.URI;\\nimport org.apache.hadoop.conf.Configuration;\\nimport org.apache.hadoop.fs.FileSystem;\\nimport org.apache.hadoop.fs.Path;\\nimport org.apache.hadoop.fs.FileStatus;\\nimport org.apache.hadoop.fs.FileUtil;\\nimport scala.collection.mutable.ArrayBuffer\\n\\n/**\\n * 主要目的是打印某个hdfs目录下所有的文件名,包括子目录下的\\n * 其他的方法只是顺带示例,以便有其它需求可以参照改写\\n */\\nobject FilesList {\\n\\n def main(args: Array[String]): Unit = {\\n\\n val path = \\"hdfs://rebuildb.hhyp75.com:9500/tmp/hive\\"\\n println(\\"打印所有的文件名,包括子目录\\")\\n\\n listAllFiles(path)\\n\\n println(\\"打印一级文件名\\")\\n\\n listFiles(path)\\n println(\\"打印一级目录名\\")\\n\\n listDirs(path)\\n println(\\"打印一级文件名和目录名\\")\\n\\n listFilesAndDirs(path)\\n\\n // getAllFiles(path).foreach(println)\\n // getFiles(path).foreach(println)\\n // getDirs(path).foreach(println)\\n }\\n\\n def getHdfs(path: String) = {\\n val conf = new Configuration()\\n FileSystem.get(URI.create(path), conf)\\n }\\n\\n def getFilesAndDirs(path: String): Array[Path] = {\\n val fs = getHdfs(path).listStatus(new Path(path))\\n FileUtil.stat2Paths(fs)\\n }\\n /**************直接打印************/\\n\\n /**\\n * 打印所有的文件名,包括子目录\\n */\\n def listAllFiles(path: String) {\\n val hdfs = getHdfs(path)\\n val listPath = getFilesAndDirs(path)\\n listPath.foreach(path => {\\n if (hdfs.getFileStatus(path).isFile())\\n println(path)\\n else {\\n listAllFiles(path.toString())\\n }\\n })\\n }\\n\\n /**\\n * 打印一级文件名\\n */\\n def listFiles(path: String) {\\n getFilesAndDirs(path).filter(getHdfs(path).getFileStatus(_).isFile()).foreach(println)\\n }\\n\\n /**\\n * 打印一级目录名\\n */\\n def listDirs(path: String) {\\n getFilesAndDirs(path).filter(getHdfs(path).getFileStatus(_).isDirectory()).foreach(println)\\n }\\n\\n /**\\n * 打印一级文件名和目录名\\n */\\n def listFilesAndDirs(path: String) {\\n getFilesAndDirs(path).foreach(println)\\n }\\n\\n /**************直接打印************/\\n /**************返回数组************/\\n def getAllFiles(path: String): ArrayBuffer[Path] = {\\n val arr = ArrayBuffer[Path]()\\n val hdfs = getHdfs(path)\\n val listPath = getFilesAndDirs(path)\\n listPath.foreach(path => {\\n if (hdfs.getFileStatus(path).isFile()) {\\n arr += path\\n } else {\\n arr ++= getAllFiles(path.toString())\\n }\\n })\\n arr\\n }\\n\\n def getFiles(path: String): Array[Path] = {\\n getFilesAndDirs(path).filter(getHdfs(path).getFileStatus(_).isFile())\\n }\\n\\n def getDirs(path: String): Array[Path] = {\\n getFilesAndDirs(path).filter(getHdfs(path).getFileStatus(_).isDirectory())\\n }\\n\\n /**************返回数组************/\\n}\\n
\\n\\n6. spark 的 wordCount 示例。
\\npackage com.xudong\\n\\nimport org.apache.spark.mllib.linalg.{Matrices, Matrix}\\nimport org.apache.spark.{SparkContext, SparkConf}\\n\\nobject TestSparkHdfs {\\n\\n def main(args: Array[String]): Unit = {\\n\\n val conf=new SparkConf().setAppName(\\"SparkHive\\").setMaster(\\"local\\") //可忽略,已经自动创建了\\n val sc=new SparkContext(conf) //可忽略,已经自动创建了\\n\\n val textFile = sc.textFile(\\"hdfs://rebuildb.fdfp75.com:9500/tmp/spark/test/workd.txt\\");\\n val counts = textFile.flatMap(_.split(\\" \\")).map((_, 1)).reduceByKey(_ + _);\\n counts.saveAsTextFile(\\"hdfs://rebuildb.fdfd75.com:9500/tmp/spark/test/wordcount/output\\");\\n\\n }\\n\\n}\\n
\\n\\npackage com.xudong\\n\\nimport org.apache.spark.mllib.linalg.{Matrices, Matrix}\\nimport org.apache.spark.{SparkContext, SparkConf}\\n\\nobject WordCountLocal {\\n\\n def main(args: Array[String]) {\\n\\n /**\\n * SparkContext 的初始化需要一个SparkConf对象\\n * SparkConf包含了Spark集群的配置的各种参数\\n */\\n val conf = new SparkConf()\\n .setMaster(\\"local\\") // 启动本地化计算\\n .setAppName(\\"testRdd\\") // 设置本程序名称\\n\\n // Spark程序的编写都是从SparkContext开始的\\n val sc = new SparkContext(conf)\\n\\n // 以上的语句等价与val sc=new SparkContext(\\"local\\",\\"testRdd\\")\\n val data = sc.textFile(\\"E:\\\\\\\\4work\\\\\\\\27java\\\\\\\\1_1_Movie_Recommend\\\\\\\\maven_scala_test\\\\\\\\src\\\\\\\\main\\\\\\\\resources\\\\\\\\hello.txt\\") // 读取本地文件\\n\\n data.flatMap(_.split(\\" \\")) // 下划线是占位符,flatMap是对行操作的方法,对读入的数据进行分割\\n .map((_, 1)) // 将每一项转换为key-value,数据是key,value是1\\n .reduceByKey(_ + _) // 将具有相同key的项相加合并成一个\\n .collect() // 将分布式的RDD返回一个单机的scala array,在这个数组上运用scala的函数操作,并返回结果到驱动程序\\n .foreach(println) // 循环打印\\n }\\n\\n}\\n
\\n\\n学习交流
\\n\\n 本作品采用《CC 协议》,转载必须注明作者和本文链接\\n\\n\\n \\n \\n
以下略过 Jmeter 介绍,也略过 Jmeter 安装方法。主要介绍项目的两个业务场景介绍,随机参数的并发请求模拟和文件提取接口请求模拟。在场景中,也涉及 Jmeter 的基本的使用方法。为了方便查看操作方法,下面是切换的简体中文语言。
\\nJdk 1.8
\\nJmeter5.4
\\n1. 添加一个线程组
\\n2. 在对应线程组添加一个请求默认值
\\n添加一个请求默认值后,后面只要是 HTTP 请求,都会只用该默认的参数值。
\\n3. 添加一个 HTTP 信息头管理器。
\\n信息头管理器可以放入接口公用的头部,因为一般的 http 接口都会要求携带一个令牌或者一些设备信息等。
\\n4. 添加一个登陆 http 请求
\\n因为大部分接口的令牌一般都是需要在登陆的接口返回值中获取,取回的值就放入 HTTP 信息头管理器中
\\n5. 当前线程组添加一个察看结果树。
\\n6. 运行线程组,结果察看数察看登陆接口返回的值并测试需要的值。
\\n7. 在登陆接口下添加一个 JSON 提取器。
\\n在提取器提取的令牌值后,HTTP 信息头管理器可以添加该信息值。
\\n当前并发测试的接口是加入购物车,而添加购物车的商品需要在另一个接口中获取符合条件的 ID。所以以下就以获取指定 ID,并发的请求购物车添加的流程为例。
\\n1. 添加一个获取商品 ID 的列表接口。
\\n先运行请求一下获取列表,查看结果数,用 JSON 格式打开返回结果。再通过表达式获取指定条件的 id 集合。
\\n2. 给商品列表按结果数测试的表达式添加一个 JSON 提取器
\\n3. 添加一个加入购物车 HTTP 请求,携带 JSON 提取器中的变量。
\\n4. 设置线程组并发数。
\\n5. 运行整个线程组后查看结果数和数据库,看看程序的判断是否异常。
\\n读取 csv 文件的值作为参数
\\n1. 创建一个只有一列的 csv 文件,里面存在根据业务而定 (举例的是库存编号)
\\n2. 添加线程组,默认请求信息,信息头。
\\n3. 添加登录接口并提取令牌值到信息头管理器中。
\\n4. 添加一个 CSV 元件。
\\n5. 设置 csv 文件取值的变量名。
\\n6. 添加接口放入 csv 取值预留的变量。
\\n7. 运行线程组,查看结果树。
\\n8. 查看数据库成功添加的数据。
\\n\\n 本作品采用《CC 协议》,转载必须注明作者和本文链接\\n\\n\\n \\n \\n
安装步骤:
1.查看是否已安装JDK
yum list installed |grep java
1
2.卸载CentOS系统Java环境
\\nyum -y remove java-1.8.0-openjdk* *代表卸载所有openjdk相关文件输入
yum -y remove tzdata-java.noarch 卸载tzdata-java
1
2
3.查看JDK软件包版本
\\nyum -y list java*
1
4.查看JDK软件包列表 安装JDK
\\nyum install -y java-1.8.0-openjdk* 自动安装java1.8.0所有程序
1
控制台返回Complete安装成功!!!
验证
java -version 查看版本信息
1
java javac 查看帮助信息
1
你如果好奇这个自动安装把jdk安装到哪里去了,其实你可以在usr/lib/jvm下找到它们。
使用yum安装环境变量自动就配好了
\\n 本作品采用《CC 协议》,转载必须注明作者和本文链接\\n\\n\\n \\n
1.随时更新最新版.\\n2.系统数据是包含其他文件的,比如说你如本机安装的mysql,数据库的文件都算系统数据.可以用 DaisyDisk 软件分析下,是什么大文件占用.\\n3.3,4个内存占用比较大还算正常吧,项目大索引多占用就比较大(某些ide的版本感觉确实卡). ide 可以限制最大占用内存,内存占用多也还好,不卡就行了.
\\n常年不关机,从来不更新 :joy:
\\n不正常,系统数据这么多。
\\n非必要不要更新大版本,能用就行。
\\n基本不用最新版本
\\n我对开发环境的要求
\\n\\n\\nPS: 大版本发布至少半年以上
\\n
du -hd1 /
我一般用这个命令检查目录占用情况, 腾讯柠檬清理好像也可以实现这个功能
我是 m1 pro 32 1t
\\n19款 pro 16 512,12.7.4,就跑下php、go、docker,感觉还能用个四五年,起码目前来说没有卡。因为是intel芯片,后面的系统就不打算升级了
\\n你下载一个 CleamMyMac ,有个空间透镜,可以排插到大文件,我电脑才500G,就是专门跑项目的,之前有一次发现硬盘占用快超过400G了,然后就用这个空间透镜查了一下,结果发现有一个200G的 PHP-FPM 错误日志文件 :sweat_smile:
\\n
给作者同配置(M1 max 32G 1TB),快两年了,不过我的PHP,MySQL,Redis,Nginx都是用docker跑的,本地只有go的环境,系统升级到14,除了navicat premium会闪退,其他的都没问题,不过现在navicat premium 升级到16.3.5也没闪退了
当我们使用@KafkaListener
注解声明一个消费者时,该消费者就会轮询去拉取对应分区消息记录,消费消息记录,正如你所知道的那样,正常场景下会执行ack
操作,提交offset
到kafka
服务器。但是异常场景下会如何执行,不知你是否也了解?在了解之前,先一起来看下异常处理器
,看完之后想必会有所收获。
在实例化org.springframework.kafka.listener.KafkaMessageListenerContainer.ListenerConsumer#ListenerConsumer
的时候如果没有自定义异常处理器,会去创建SeekToCurrentErrorHandler
作为默认异常处理器使用
typescript
\\n复制代码
\\nprotected ErrorHandler determineErrorHandler(GenericErrorHandler<?> errHandler) {\\n return errHandler != null ? (ErrorHandler) errHandler\\n : this.transactionManager != null\\n ? null : new SeekToCurrentErrorHandler();\\n}
\\n\\n在构建默认异常处理器SeekToCurrentErrorHandler
时会指定对应的补偿策略
csharp
\\n复制代码
\\n/**\\n * Construct an instance with the default recoverer which simply logs the record after\\n * {@value SeekUtils#DEFAULT_MAX_FAILURES} (maxFailures) have occurred for a\\n * topic/partition/offset, with the default back off (9 retries, no delay).\\n * [@since](https://learnku.com/users/65735) 2.2\\n */\\npublic SeekToCurrentErrorHandler() {\\n this(null, SeekUtils.DEFAULT_BACK_OFF);\\n}
\\n\\n\\n\\n从代码注释上我们可以了解到该补偿策略会进行9次无时间间隔重试
\\n
scss
\\n复制代码
\\n@Nullable\\nprivate RuntimeException doInvokeRecordListener(final ConsumerRecord<K, V> record, // NOSONAR\\n Iterator<ConsumerRecord<K, V>> iterator) {\\n Object sample = startMicrometerSample();\\n\\n try {\\n // 1.消费消息\\n invokeOnMessage(record);\\n successTimer(sample);\\n recordInterceptAfter(record, null);\\n } catch (RuntimeException e) {\\n try {\\n // 2.执行异常处理器\\n invokeErrorHandler(record, iterator, e);\\n // 3.提交offset\\n commitOffsetsIfNeeded(record);\\n } catch (KafkaException ke) {\\n\\n }\\n }\\n return null;\\n}
\\n\\n\\n\\n这里可以看到当消息消费异常后,会调用默认异常处理器
\\nSeekToCurrentErrorHandler
csharp
\\n复制代码
\\npublic static boolean doSeeks(List<ConsumerRecord<?, ?>> records, Consumer<?, ?> consumer, Exception exception,\\n boolean recoverable, RecoveryStrategy recovery, @Nullable MessageListenerContainer container,\\n LogAccessor logger) {\\n\\n Map<TopicPartition, Long> partitions = new LinkedHashMap<>();\\n AtomicBoolean first = new AtomicBoolean(true);\\n AtomicBoolean skipped = new AtomicBoolean();\\n records.forEach(record -> {\\n if (recoverable && first.get()) {\\n try {\\n // 1.判断该消息是否可重试\\n boolean test = recovery.recovered(record, exception, container, consumer);\\n skipped.set(test);\\n }\\n catch (Exception ex) {\\n }\\n }\\n if (!recoverable || !first.get() || !skipped.get()) {\\n partitions.computeIfAbsent(new TopicPartition(record.topic(), record.partition()),\\n offset -> record.offset());\\n }\\n first.set(false);\\n });\\n // 2.重置分区偏移量,以便可以重复拉取异常消息\\n seekPartitions(consumer, partitions, logger);\\n return skipped.get();\\n}
\\n\\n\\n\\n异常处理器执行过程:
\\n判断当前消息是否可重试
\\n如果当前消息可以重试,会将该消息对应
\\noffset
存储在partitions
中,紧接着通过seekPartitions
方法来将当前分区offset
重置为当前消息offset
,以至在下一次拉取消息的时候,仍然可以拉取到该异常消息。如果当前消息不可以重试,判断此次拉取的消息是否只有一条,如果是,不做处理;如果不是,则通过
\\npartitions.computeIfAbsent
方法设置分区offset
为异常消息下一条消息对应offset
,以至在下一次拉取的时候可以拉取到异常消息后的其它消息。
csharp
\\n复制代码
\\n@Nullable\\nprivate RuntimeException doInvokeRecordListener(final ConsumerRecord<K, V> record, // NOSONAR\\n Iterator<ConsumerRecord<K, V>> iterator) {\\n\\n Object sample = startMicrometerSample();\\n\\n try {\\n invokeOnMessage(record);\\n }\\n catch (RuntimeException e) {\\n try {\\n invokeErrorHandler(record, iterator, e);\\n // 提交分区offset\\n commitOffsetsIfNeeded(record);\\n } catch (KafkaException ke) {\\n }\\n }\\n return null;\\n}
\\n\\n\\n\\n当默认异常处理器重试达到最大次数
\\n9
次后,会执行commitOffsetsIfNeeded
方法,手动提交分区offset
当消费消息异常,在没有声明异常处理器的前提下会选择使用默认异常处理器SeekToCurrentErrorHandler
,默认异常处理器会对异常消息进行重试,在达到最大重试次数9
次后,会手动提交异常消息offset
,然后继续消费异常消息之后的其它消息。
至此想必对消息消费异常有了一个大致认识,如有疑问,欢迎留言讨论。
\\n作者:黑白搬砖工
链接:juejin.cn/post/7160650750995988493
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
\\n 本作品采用《CC 协议》,转载必须注明作者和本文链接\\n\\n\\n \\n
\\n\\n很多优秀的开发者都喜欢使用 Mac进行开发工作,笔者也是如此,所以整理了一下个人觉得好用的软件和工具,以及相关的设置并分享出来,欢迎大家互相交流探索。
\\n
对于那些全能型的全栈开发者们来说,Mac系统己经成了他们的得力助手。
\\n原因很简单:Mac既稳定又快,开发起来头疼点少,效率高。再加上它对开发者特别友好,安装各种工具和设置环境都很简单,主打一个顺滑流畅。
\\n接下来就由我介绍一下几个特别适合在Mac上使用的开发工具。这些工具就像是你的开发小助手,无论你是在搞前端设计,还是后端逻辑,甚至是数据库的管理,它们都能帮你搞定。
\\n\\n\\n\\nPostman是一个强大的API开发和测试工具,支持Mac系统。它提供了一个直观的用户界面,用于创建、发送请求和检查响应,支持多种类型的API测试,如REST、SOAP等。Postman还支持自动化测试、环境变量管理和API文档生成,是API开发和测试的理想选择。
\\n
\\n\\n\\nSequel Pro是针对Mac用户设计的MySQL数据库管理工具,提供了一个直观的图形界面,用于数据库的管理和操作。TablePlus是另一款强大的数据库管理工具,支持多种数据库,如MySQL、PostgreSQL、SQLite等,提供了更广泛的数据库支持和更多高级功能,如内置SSH、数据库备份和还原等。
\\n
免费替代品推荐:TablePlus
\\n\\n\\n\\nHomebrew 是一个命令行包管理器工具,像管理软件包一样集中管理你的第三方软件,支持 Mac / Linux
\\n
\\n\\nMac 最为流行的终端软件非
\\nItem2
莫属, 但 Warp 横空出世了,尽管曾经我对该软件需要注册帐号来使用表达过质疑,但是相比提升的效率和更加好的开发体验,还是真香了, 可以说 Warp 就是一个 现代终端 应该有的样子。
\\n\\nServBay 是一款专为macOS设计的本地**Web开发环境**,它集成了最流行的Caddy服务器,MariaDB和PostgreSQL数据库,Redis、Memcached等NoSQL数据库,还有phpMyAdmin、adminer等数据库管理工具。它提供了同时运行多个主机的能力,支持使用尚未存在的TLDs自定义域名,为开发者提供免费SSL证书,并且通过本地DNS服务简化本地网络请求的路由和管理。
\\n
此外,它还包括一个独立的开发包,允许开发者重新编译和集成独特或自定义构建的软件,极大地增强了Web和PHP开发的流畅性和效率。凭着对新手的友好,易操作和强大的自定义功能,它已经成为新生代PHP和Nodejs开发人员的首选。了解相关
\\n\\n\\nOrbStack 是运行 Docker 容器和 Linux 的快速、轻便且简单的方法。 Docker Desktop 替代方案以光速进行开发。
\\n
官方的 Docker Compose 非常耗费系统资源,即便是 MacBook Pro M1 pro + 16g ram, 运行 2~3个 容器, 系统也会非常卡顿,苹果的内存又比金子还贵,于是出现了完美替代品 - OrbStack。OrbStack 对 CPU 和磁盘的使用率低,对内存的需求少,而且是一款原生的 Swift 应用程序,可以无缝运行 Docker 容器和完整的 Linux 发行版,并提供强大的网络功能。个人可以完全免费使用!
\\n\\n\\n\\nSurge是适用于 Mac 和 iOS 的高级网络工具箱,满足您对网络的一切个性化,如流畅访问Github, ChatGPT 等,嗯,很常见的开发需求。
\\n
需要注意的是: Mac 和 iOS 版本是分开的,需要单独购买, iOS 版本附赠 Apple TV 版本的 TV OS版, 借助 Apple TV 可以实现一些比较 amazing 的功能。了解相关
\\n\\n\\n\\nDash 是一个离线文档浏览器和代码片段管理器,开发者需要经常翻阅技术文档来查询某个API的用法,那么下载到 Dash 离线的观看体验更加良好。
\\n
\\n\\n许多框架和服务都提供 Slack / Discord 的联系方式, 通过 Discord 可以第一时间接收官方的一手消息,以及聆听社区的反馈。
\\nDiscord 的用户体验和开发体验都是非常优秀的, 比如你可以在自己的频道(植入bot和插件,api等等,如chatGPT机器人,群管理机器人等等,如果你有参与开源项目的打算,Discord 是非常推荐的~
\\n
\\n\\nMac 最好用的 Gif 图制作软件 简单快捷的操作同时带键位记录, 非常合适录制一些gif图。
\\n
\\n\\n密码管理这块, 综合最佳还是老牌的 1Password, 省去靠大脑记密码还会弄丢的尴尬场景,输入密码只需要通过
\\nCommand + /
一键调出。
尽管目前 passkey (通行密钥) 等无密码登录方式正在逐渐走向现实,但如今依然离不开密码,所以暂时来说有一个密码管理器还是能提升许多效率的。
\\n免费替代品推荐:Chrome Password Manager / Bitwarden / iCloud Password & KeyChains
\\n\\n\\n原本使用的是开源免费的
\\nSnipaste X
**, 发现有更好用的**Clean Shot X
且在 setapp 里, 支持 orc识图提取文字, 贴图, 滚动截图等功能,是 Mac 上功能比较全面的截图软件,**可通过订阅 setapp 免费获取
**
替代品推荐: Snipaste / iShot / Shottr / Xnip
\\n选择合适的工具,可以帮助你更加轻松地应对全栈开发的挑战,实现高效的开发流程。总之,作为一个以编码为主的开发者,个人所使用过且推荐的暂且就这么多,后续有新的软件分享也会持续更新,希望对你有所收获。
\\n\\n \\n\\n 本作品采用《CC 协议》,转载必须注明作者和本文链接\\n\\n\\n \\n
这是不是一篇 seo 文章?
\\n#案例分享
\\n昨天给大家布置了一道题目,关于加薪、奖金的分配的。
\\n这里给大家看培训企业的一些代表性观点:
\\n【逻辑一】从人才稀缺性来考虑
\\n答案示例:丙作为资深工程师,表现及格,但因为资深工程师具有稀缺性,假如团队内没有backup,一旦流失,损失较大,需要提供有竞争力的加薪和奖金方案;乙作为新鲜血液,过往一年的表现属于高绩效人员,可以给与一定倾斜的奖金和调薪;
甲刚刚晋升高级,表现基本符合预期,可以给与平均水平的奖金及调薪。”
【逻辑二】从收入起点来考虑
\\n甲加,乙大加,丙小加。鼓励甲乙的成长和丙的贡献,同时也要看他们对工资的期待,比如通常甲这样的员工生活中可能需要买房或者还贷款,乙处于刚入职工资本来就低于平均水平,丙工资本来就高加上今年的表现可以少加点,应该能满足生活中资金需求。
\\n【逻辑三】从职级来考虑
\\n奖金的优先级:资深工程师 > 高级工程师 > 初级工程师 加薪的优先级:乙 > 丙 > 甲 理由: 奖金:从团队稳定性的角度来说,资深工程师培养的成本最高,发生动荡对团队的损失最大。而资深工程师只要是稳定发挥,对团队的贡献肯定是最大的,需要从团队贡献角度来分配奖金,能者多得。高级工程师次之,初级工程师还需要团队培养,需要时间,可以放在最后。 加薪:加薪应该奖励进步明显者,加薪突出的是成长性,鼓励员工保持积极性,保持学习。甲由于表现只能基本符合预期,所以排在加薪最后。
\\n【逻辑四】从贡献来考虑
\\n“奖金:乙>甲>丙
加薪:乙>丙>甲
个人意见如下:
1 突出贡献的,无论能力,级别,都应该给予最高奖励,鼓励员工积极性 。
2 对于刚升职的员工,如果可以基本符合预期,那么证明能力的确达到了这个级别,但是暂时不具备更向上一级的能力。
3 对于丙,已经是资深的程序员,向上发展有困难,也很难驱动。需要在奖金方面做一些调整,此外薪水涨幅需要给予鼓励,以免发生离职,越 senior 越容易离职,所以薪水需要保持在外界相同 level,但是由于贡献一般,奖金可以少给一些,并且在奖金发放的时候,解释一下,鼓励激发 senior 员工。”
加薪: 背后的理念是企业认为员工达到了下一个阶段能力水平的要求,未来可以承担更大的责任和挑战。是为『未来』付薪。
\\n奖金: 奖金背后的理念是企业认为员工过去做出了贡献,体现出业绩和结果。是为『过去』付款。
\\n明白了这两地,再来看作业中的几个例子,就会很清晰地知道处理原则了。
\\n甲: 晋升了就应该加薪,但表现基本符合预期,没有超越期望。按公司制度发放奖金即可。
\\n乙: 过去的业绩超越预期,应该体现在奖金上,有额外的回报。但没有晋升,说明目前能力可能还不足以支撑长期、持续性、一贯性的更高级别的挑战。不一定需要加薪。而是鼓励其争取向更高一级的岗位挑战,在成功晋升后再给予加薪。
\\n丙: 表现不好不坏,维持在60分及格水准。这个时候按公司制度发放奖金,已经决定是否需要跟随普调即可。更关键的是要和当事人谈,看看是哪些因素让丙两年都没有亮点,给予帮助,设定下一阶段突破的目标。
\\n这道题目,关键不在于加多加少,而在于你给别人『发钱』的时候,能够清清楚楚地讲出,我为什么要给你加?为什么只加奖金不加薪?为什么这次比上次多/少?
\\n发钱要发得明明白白,才能起到激励的效果。
\\n至于前面说用钱留人的,不是不可以,但小心一点: 激励制度不是用来交易的。用钱可以留住人一会,但要长远留住人,还得靠『个人成就感和价值体现』。
\\n上周去给一家企业上课,课前给企业员工留了几道作业。其中有一道题目,答案分歧很大。这里贴出来给大家看看,看看大家都有什么观点。
\\n——————————
\\n如果你有权决定下列员工的加薪、奖金,你的方案是什么?理由呢?
\\n甲:刚刚晋升为高级工程师,过往一年业绩表现基本符合预期。
\\n乙:作为初级工程师,过去一年在业务上做出了超越预期的贡献。
\\n丙:资深工程师,最近两年表现维持在同一水平。不好也不坏。
\\n\\n \\n\\n 本作品采用《CC 协议》,转载必须注明作者和本文链接\\n\\n\\n \\n
\\n\\n有个 xx 需求,我应该用 Kafka 还是 RabbitMQ ?
\\n
这个问题很常见,而且很多人对二者的选择也把握不好。
所以我决定写篇文章来详细说一下:Kafka 和 RabbitMQ 的区别,适用于什么场景?
\\n同时,这个问题在面试中也经常问到。
\\n下面我会通过 6 个场景,来对比分析一下 Kafka 和 RabbitMQ 的优劣。
\\n有这样一个需求:当订单状态变化的时候,把订单状态变化的消息发送给所有关心订单变化的系统。
\\n订单会有创建成功、待付款、已支付、已发货的状态,状态之间是单向流动的。
\\n好,现在我们把订单状态变化消息要发送给所有关心订单状态的系统上去,实现方式就是用消息队列。
\\n在这种业务下,我们最想要的是什么?
\\n消息的顺序:对于同一笔订单来说,状态的变化都是有严格的先后顺序的。
\\n吞吐量:像订单的业务,我们自然希望订单越多越好。订单越多,吞吐量就越大。
\\n在这种情况下,我们先看看 RabbitMQ 是怎么做的。
\\n首先,对于发消息,并广播给多个消费者这种情况,RabbitMQ 会为每个消费者建立一个对应的队列。也就是说,如果有 10 个消费者,RabbitMQ 会建立 10 个对应的队列。然后,当一条消息被发出后,RabbitMQ 会把这条消息复制 10 份放到这 10 个队列里。
\\n当 RabbitMQ 把消息放入到对应的队列后,我们紧接着面临的问题就是,我们应该在系统内部启动多少线程去从消息队列中获取消息。
\\n如果只是单线程去获取消息,那自然没有什么好说的。但是多线程情况,可能就会有问题了……
\\nRabbitMQ 有这么个特性,它在官方文档就声明了自己是不保证多线程消费同一个队列的消息,一定保证顺序的。而不保证的原因,是因为多线程时,当一个线程消费消息报错的时候,RabbitMQ 会把消费失败的消息再入队,此时就可能出现乱序的情况。
\\nT0 时刻,队列中有四条消息 A1、B1、B2、A2。其中 A1、A2 表示订单 A 的两个状态:待付款、已付款。B1、B2 也同理,是订单 B 的待付款、已付款。
\\n到了 T1 时刻,消息 A1 被线程 1 收到,消息 B1 被线程 2 收到。此时,一切都还正常。
\\n到了 T3 时刻,B1 消费出错了,同时呢,由于线程 1 处理速度快,又从消息队列中获取到了 B2。此时,问题开始出现。
\\n到了 T4 时刻,由于 RabbitMQ 线程消费出错,可以把消息重新入队的特性,此时 B1 会被重新放到队列头部。所以,如果不凑巧,线程 1 获取到了 B1,就出现了乱序情况,B2 状态明明是 B1 的后续状态,却被提前处理了。
\\n所以,可以看到了,这个场景用 RabbitMQ,出现了三个问题:
\\n那么 Kafka 怎么样呢?Kafka 正好在这三个问题上,表现的要比 RabbitMQ 要好得多。
\\n首先,Kafka 的发布订阅并不会复制消息,因为 Kafka 的发布订阅就是消费者直接去获取被 Kafka 保存在日志文件中的消息就好。无论是多少消费者,他们只需要主动去找到消息在文件中的位置即可。
\\n其次,Kafka 不会出现消费者出错后,把消息重新入队的现象。
\\n最后,Kafka 可以对订单进行分区,把不同订单分到多个分区中保存,这样,吞吐量能更好。
\\n所以,对于这个需求 Kafka 更合适。
\\n我曾经做过一套营销系统。这套系统中有个非常显著的特点,就是非常复杂非常灵活地匹配规则。
\\n比如,要根据推广内容去匹配不同的方式做宣传。又比如,要根据不同的活动去匹配不同的渠道去做分发。
\\n总之,数不清的匹配规则是这套系统中非常重要的一个特点。
\\n首先,先看看 RabbitMQ 的,你会发现 RabbitMQ 是允许在消息中添加 routing_key 或者自定义消息头,然后通过一些特殊的 Exchange,很简单的就实现了消息匹配分发。开发几乎不用成本。
\\n而 Kafka 呢?如果你要实现消息匹配,开发成本高多了。
\\n首先,通过简单的配置去自动匹配和分发到合适的消费者端这件事是不可能的。
\\n其次,消费者端必须先把所有消息不管需要不需要,都取出来。然后,再根据业务需求,自己去实现各种精准和模糊匹配。可能因为过度的复杂性,还要引入规则引擎。
\\n这个场景下 RabbitMQ 扳回一分。
\\n在电商业务里,有个需求:下单之后,如果用户在 15 分钟内未支付,则自动取消订单。
\\n你可能奇怪,这种怎么也会用到消息队列的?
\\n我来先简单解释一下,在单一服务的系统,可以起个定时任务就搞定了。
\\n但是,在 SOA 或者微服务架构下,这样做就不行了。因为很多个服务都关心是否支付这件事,如果每种服务,都自己实现一套定时任务的逻辑,既重复,又难以维护。
\\n在这种情况下,我们往往会做一层抽象:把要执行的任务封装成消息。当时间到了,直接扔到消息队列里,消息的订阅者们获取到消息后,直接执行即可。
\\n希望把消息延迟一定时间再处理的,被称为延迟队列。
\\n对于订单取消的这种业务,我们就会在创建订单的时候,同时扔一个包含了执行任务信息的消息到延迟队列,指定15分钟后,让订阅这个队列的各个消费者,可以收到这个消息。随后,各个消费者所在的系统就可以去执行相关的扫描订单的任务了。
\\n先看下 RabbitMQ 的。
\\nRabbitMQ 的消息自带手表,消息中有个 TTL 字段,可以设置消息在 RabbitMQ 中的存放的时间,超时了会被移送到一个叫死信队列的地方。
\\n所以,延迟队列 RabbitMQ 最简单的实现方式就是设置 TTL,然后一个消费者去监听死信队列。当消息超时了,监听死信队列的消费者就收到消息了。
\\n不过,这样做有个大问题:假设,我们先往队列放入一条过期时间是 10 秒的 A 消息,再放入一条过期时间是 5 秒的 B 消息。 那么问题来了,B 消息会先于 A 消息进入死信队列吗?
\\n答案是否定的。B 消息会优先遵守队列的先进先出规则,在 A 消息过期后,和其一起进入死信队列被消费者消费。
\\n在 RabbitMQ 的 3.5.8 版本以后,官方推荐的 rabbitmq delayed message exchange 插件可以解决这个问题。
\\n再看下 Kafka 的:
\\nKafka 要实现延迟队列就很麻烦了。
\\n想想就已经头大了,这都快搞成调度平台了。再高级点,还要用时间轮算法才能更好更准确。
\\n这次,RabbitMQ 上那一条条戴手表的消息,才是最好的选择。
\\n在微服务里,事件溯源模式是经常用到的。如果想用消息队列实现,一般是把事件当成消息,依次发送到消息队列中。
\\n事件溯源有个最经典的场景,就是事件的重放。简单来讲就是把系统中某段时间发生的事件依次取出来再处理。而且,根据业务场景不同,这些事件重放很可能不是一次,更可能是重复 N 次。
\\n假设,我们现在需要一批在线事件重放,去排查一些问题。
\\nRabbitMQ 此时就真的不行了,因为消息被人取出来就被删除了。想再次被重复消费?对不起。
\\n而 Kafka 呢,消息会被持久化一个专门的日志文件里。不会因为被消费了就被删除。
\\n所以,对消息不离不弃的 Kafka 相对用过就抛的 RabbitMQ,请选择 Kafka。
\\n很多时候,在做记录数据相关业务的时候,Kafka 一般是不二选择。不过,有时候在记录数据吞吐量不大时,我自己倒是更喜欢用 RabbitMQ。
\\n原因就是 Kafka 有一个我很不喜欢的设计原则:
\\n当单个分区中的消息一旦出现消费失败,就只能停止而不是跳过这条失败的消息继续消费后面的消息。即不允许消息空洞。
\\n只要消息出现失败,不管是 Kafka 自身消息格式的损坏,还是消费者处理出现异常,是不允许跳过消费失败的消息继续往后消费的。
\\n所以,在数据统计不要求十分精确的场景下选了 Kafka,一旦出现了消息消费问题,就会发生项目不可用的情况。这真是徒增烦恼。
\\n而 RabbitMQ 呢,它由于会在消息出问题或者消费错误的时候,可以重新入队或者移动消息到死信队列,继续消费后面的,会省心很多。
\\n坏消息就像群众中的坏蛋那样,Kafka 处理这种坏蛋太过残暴,非得把坏蛋揪出来不行。相对来说,RabbitMQ 就温柔多了,群众是群众,坏蛋是坏蛋,分开处理嘛。
\\nKafka 是每秒几十万条消息吞吐,而 RabbitMQ 的吞吐量是每秒几万条消息。
\\n其实,在一家公司内部,有必须用到 Kafka 那么大吞吐量的项目真的很少。大部分项目,像 RabbitMQ 那样每秒几万的消息吞吐,已经非常够了。
\\n在一些没那么大吞吐量的项目中引入 Kafka,我觉得就不如引入 RabbitMQ。
\\n为什么呢?
\\n因为 Kafka 为了更好的吞吐量,很大程度上增加了自己的复杂度。而这些复杂度对项目来说,就是麻烦,主要体现在两个方面:
\\n1、配置复杂、维护复杂
\\nKafka 的参数配置相对 RabbitMQ 是很复杂的。比如:磁盘管理相关参数,集群管理相关参数,ZooKeeper 交互相关参数,Topic 级别相关参数等,都需要一些思考和调优。
\\n另外,Kafka 本身集群和参与管理集群的 ZooKeeper,这就带来了更多的维护成本。Kafka 要用好,你要考虑 JVM,消息持久化,集群本身交互,以及 ZooKeeper 本身和它与 Kafka 之间的可靠和效率。
\\n2、用好,用对存在门槛
\\nKafka 的 Producer 和 Consumer 本身要用好用对也存在很高的门槛。
\\n比如,Producer 消息可靠性保障、幂等性、事务消息等,都需要对 KafkaProducer 有深入的了解。
\\n而 Consumer 更不用说了,光是一个日志偏移管理就让一大堆人掉了不少头发。
\\n相对来说,RabbitMQ 就简单得多。你可能都不用配置什么,直接启动起来就能很稳定可靠地使用了。就算配置,也是寥寥几个参数设置即可。
\\n所以,大家在项目中引入消息队列的时候,真的要好好考虑下,不要因为大家都鼓吹 Kafka 好,就无脑引入。
\\n可以看到,如果我们要做消息队列选型,有两件事是必须要做好的:
\\n列出业务最重要的几个特点
\\n深入到消息队列的细节中去比较
\\n等我们对这些中间件的特点非常熟悉之后,甚至可以把业务分解成不同的子业务,再根据不同的子业务的特征,引入不同的消息队列,即消息队列混用。这样,我们就可能会最大化我们的获益,最小化我们的成本。
\\n说了这么多,其实还有很多 Kafka 和 RabbitMQ 的比较没有说,比如二者集群的区别,占用资源多少的比较等。以后有机会可以再提提。
\\n总之,期待大家看完这篇文章后,能对 Kafka 和 RabbitMQ 的区别有了更细节性的了解。
\\n最后,分享一个网上的比较全的对比图:
\\n原文地址:Kafka和RabbitMQ有哪些区别,各自适合什么场景? - 四猿外 - 博客园
\\n\\n \\n\\n 本作品采用《CC 协议》,转载必须注明作者和本文链接\\n\\n\\n \\n
项目名称:version-manager
\\n项目简介:
vm 是一个简单,跨平台,并且经过良好测试的版本管理工具。它完全是为了通用目的而创建的。你不需要任何插件,只需要 vm 就可以管理所有东西。
可能你已经听说过 sdkman, gvm, nvm, pyenv, phpenv 等工具。然而,这些工具都不能管理多种编程语言。vm支持了国内程序员常用的几乎所有编程语言,并且支持了vlang、zig、typst等新兴的有一定潜力的语言。不管你是老鸟还是菜鸟,它都能给你带来一定的便利。你不用手动去找任何资源,就能轻松安装管理各种版本,尝试新的语言,新的特性。vm将这些sdk或工具集中管理,对于有洁癖的人来说,也是福音。
\\nMacOS演示
\\nWindows演示
\\nLinux演示
\\n\\n 本作品采用《CC 协议》,转载必须注明作者和本文链接\\n\\n\\n \\n
效果:
\\n2023-01-31151
\\n自动显示注释,在阅读源码时比较实用,能迅速了解代码表达的意思,当然排除注释不真实的情况哈,这里列举几个实例。
\\n可针对注释的展现形式进行全局配置,如文本颜色、显示行数、前缀等。
\\n也可对项目注释是否展示进行配置,配置包含正则和排除正则表达式。
\\n在对项目不太熟悉的情况下,对于快速了解项目,梳理业务逻辑,此插件还是比较实用的,提升工程熟悉进度。
\\n\\n \\n\\n 本作品采用《CC 协议》,转载必须注明作者和本文链接\\n\\n\\n \\n
图全裂开了
\\n在写脚本测试,经常会创建额外目录,但是每次都要添加到 .gitignore
,就很烦。
所以想利用.gitignore
只提交固定文件。
.gitignore
.gitignore
git init .
git add -f ./*
把当前目录所有文件提交
这样就可以实现,只提交固定文件了。
\\n\\n \\n\\n 本作品采用《CC 协议》,转载必须注明作者和本文链接\\n\\n\\n \\n \\n
作为程序员,学习肯定经常的,学到的知识,如果不记下来,过不了多久就忘了,还有,工作中你灵感迸发的好代码,你折腾了很久才实现的好代码,你如果不记录下来,过段时间,你都不记得源文件放哪了,下次还得重新折腾,没错,你需要第二大脑,这就是今天要介绍的主角 Obsidian 笔记。
\\n认真记过笔记的人都知道,笔记种类有很多种,我用过有道,印象,为知,Typora,Notion,语雀,思源,logseq,最终选择了 Obsidian,因为它支持多平台,支持 Markdown,支持代码高亮,支持双链,支持白板和日记,支持语音输入,本地存储,也可以通过插件和网盘等同步,插件丰富,强大的社区支持。只有你想不到的,没有它做不到的,即使做不到,还可以用插件弥补嘛。诚然,这些功能其他笔记软件也可能有,但 Obsidian 有着丰富的插件,是其他笔记所不具备的,即使都不能满足,你还能自己开发,程序员开发个小插件还不是小 Case 嘛。
\\n最重要的是你的文档可以自己掌控,其他很多软件,笔记都是保存到服务器上,而且是自定义格式,安全问题不提,哪天服务器挂了,你辛辛苦苦记录的文档就烟消云散了,而 Obsidian 不用担心这些,你的文档在你自己的电脑上,在你自己的网盘上,你高兴放哪放哪,而且它是开放格式的 Markdown 存储,哪怕 Obsidian 不能用了,你用其他软件也可以照常打开使用嘛。
\\n最后,让我选择它的还有一个原因,可以掌控自己的笔记,其他软件,你用着不爽,想自定义很难,Obsidian 不一样,它从主题样式,到快捷键,到笔记功能,你几乎可以随心所欲的掌控,如果你愿意开发插件,那更是无所不能了,如果你懒,众多的插件也几乎能帮你实现你想要的大多数功能。
\\n甚至她还可以支持把 vscode 的编辑器嵌入到笔记写代码,而且它的代码还可以通过插件直接运行,支持多语言,哈哈哈。
\\n另外,它还能通过插件支持标注,分享,剪藏,发布或生成博客,数据加密,与云盘或服务器同步等。
\\n先睹为快:
\\n官方地址:Obsidian - Sharpen your thinking
\\n软件安装完成后建议设置“文件与链接”里的附件存放目录,推荐放到指定文件夹,附件文件夹路径是相对于你的笔记仓库的相对路径。
\\nMarkdown 语法支持,请参考官方文档:格式化笔记 - Obsidian 中文帮助 - Obsidian Publish
\\n关系图谱: 类似标签云,只不过是文章的关联关系图,这可是 Obsidian 主打的卖点,方便查看哪些文章是你知识的核心。
\\n出链和入链: 文章被引用和引文的文章列表,也是 obsidian 的卖点。
\\n文档属性: 是 yaml 格式的 frontmatter 信息,是文章的特征描述,有些软件通过这些信息进行文件管理。
\\n文件恢复: 这个功能开启后,会对 Markdown 文档产生快照,可以恢复历史数据。
\\n斜杠命令: 在编辑器中输入 /
即可触发命令面板,方便快捷选择命令。
Obsidian 的第三方插件都是开源的,你不仅可以方便的使用,不满意还可以自己调整。
\\n由于 GitHub 有时访问不稳定,建议使用 Watt Toolkit 进行加速。
\\nBartender - 首先推荐这个插件,因为这个插件可以对分类进行拖动和排序,非常方便。但这个插件并未发布到插件市场,下载地址:Site Unreachable,由于这个插件在 1.5.8 下面有个 bug,导致左侧分类空白,请到这里下载已解决的安装包 issues。
\\nRemotely Save - 多端同步插件,支持全平台,第三方服务支持 Amazon S3 系列,Dropbox,One Drive,Webdav 等。
\\nQuick Explorer - 快速浏览和导航笔记文件及文件夹结构的插件,类似于面包屑功能。
\\nQuickAdd - 快速创建新笔记或添加内容至现有笔记,简化工作流。
\\nRecentFiles - 显示最近打开过的文件列表,方便快速访问。
\\nLocal images - 把远程图片下载到本地等。
\\nAdvanced URI - 提供高级 URI 解析和跳转功能,在其他软件中可以打开或编辑 obsidian 里的笔记等,很多插件依赖它,建议安装。
\\nTemplater - 创建自定义模板,便于快速新建标准化格式的笔记,支持 js 语法,功能特别强大。
\\nBetter Export PDF - 导出的 PDF 带目录,比官方的更好。
\\nBetter Word Count - 提供更精确的字数统计,支持选中文本统计字数。
\\nBRAT - 如果你不知道怎样手动安装插件,用这个插件只需要输入 github 的作者和项目名即可下载。
\\nCalendar - 在 Obsidian 中集成日历视图,方便查看和关联时间相关的笔记。
\\nClear Unused Images - 清理不再被引用的图片资源。
\\nCommander - 这个功能非常强大,可以增加侧边栏和顶部,状态栏,右键菜单等菜单项,还支持宏命令,批量执行命令。
\\nTimeline - 增加时间线视图功能。
\\nTinyPNG Image - 对图片进行压缩优化,减小文件大小。
\\nWebpage HTML Export - 将笔记内容以 HTML 形式导出成网页,然后可以发布到博客,类似于 hexo 等。
\\nStatus Bar Pomodoro Timer - 整合番茄钟计时器在状态栏上,帮助用户执行番茄工作法。
\\nStyle Settings - 如果你使用别人的主题,使用这个插件可以便捷的开关某些样式。
\\nMySnippets - 如果你有自定义的代码片段,用这个插件方便修改和开关代码片段。
\\nSurfing - 让你的笔记像浏览器一样,可以浏览网页。
\\nSyncFTP - 把你的笔记同步到 ftp 上。
\\nSelf-hosted LiveSync - 把你的笔记同步到你自己的服务器上。
\\nTag Wrangler - 更好地管理和组织标签系统,批量查看和修改标签。
\\nRunJS - 直接在 Obsidian 中运行 JavaScript 代码,可以调用 node 和 obsidian api。
\\nShare as Gist - 把你的代码片段分享到 github Gist。
\\nJust Share Please - 方便分享笔记到 web 平台发给别人分享。
\\nQuail - 一个博客平台,允许你的笔记直接分享到这个笔记平台上,这个平台简洁漂亮,速度快,推荐。
\\nObsidian shared to Notion - 把你的笔记分享到Notion。
\\nEmoji ToolBar - 添加表情符号工具栏,方便插入表情符号。
\\nExcalidraw - 集成 Excalidraw 绘图工具,支持创建手绘风格流程图等。
\\nExecuteCode - 在笔记中执行代码片段并展示结果。
\\nFile Color - 给你的笔记标题添加颜色,更醒目,方便查看。
\\nFile explorer Note count - 显示你的文件夹内的笔记数量。
\\nCustom Frames - 内嵌 webkit 浏览器,可以把一些网站内嵌到笔记内当做笔记自己的面板。
\\nDataview - 数据统计和可视化,支持 js 和类似 SQL 的语法筛选。
\\nEasy Typing - 自动转换中文和英文标点符号格式,当你在中文输入法下,按两次中文标点或符号变成英文半角格式。
\\nEditing ToolBar - 可视化编辑器工具条。
\\nKanban - 生成支持看板功能的笔记,工作计划管理很有用。
\\nHot Reload - 热加载,如果你打算开发插件,很有用,你修改了代码,界面会立即生效。
\\nHover Editor - 把你的笔记或面板悬浮起来,方便使用。
\\nHtml Server - 如果你在公司局域网内,想把笔记分享给同事看,这个插件很有用,它可以在你笔记里启动一个小型 web 服务器,然后把链接发给你同事看,你的改动能实时在页面上看到变化,很方便。
\\nIconize - 给你的文件夹加上漂亮的图标。
\\nMulti-Column Markdown - 支持多列布局,如果你用于功能对比,用这个插件非常方便,比如我常用这个对比翻译,左边是原文,右边是译文。
\\nImage auto upload Plugin - 它可以配合 PicGo 上传图片到图床。
\\nImage Upload Toolkit - 自动上传图片到云端存储(例如阿里云 OSS 等)。
\\nMantouAI - 通义千问插件,如摘要生成、关键词提取,文章总结,向它提问等。
\\nobsidian echarts - 集成 ECharts 库,实现复杂的数据可视化图表。
\\nObsidian Memos - 创建和管理备忘录类的小型便签,类似浮墨。
\\nMarp Slides - 将 Markdown 转换为幻灯片演示文稿,只需要用分割线分割你的内容即可。
\\nMeld Encrypt - 把你的笔记加密,通常用于敏感数据,如账号等。
\\nInline Encrypter - 提供行内加密功能,文本的某一行加密。
\\nMind Map - 将笔记列表内容转换为思维导图。
\\nMulti Tag - 批量给多个笔记添加多个标签。
\\nIcon ShortCodes - 输入双冒号,快速插入各种图标。
\\nEmo 如果你想把你的图片传到 GitHub 并用配合 jsdelivr 做图床,这个插件很有用。
\\nAuto Link Title - 把链接直接转换为带有标题的链接,标题自动从网站抓取。
\\nShell commands - 快速执行 shell 脚本,可以调用本地命令打开外部应用或执行脚本等。
\\nVarious Complements - 提供了一些功能增强自动填充能力,可以为用户提供更好的使用体验和工作效率。
\\nReminder - 可以为你的任务增加提醒,并且可以联动的系统,在系统通知区域显示待办提醒。
\\nPandoc Plguin - 增加将笔记导出各种文件格式的能力例如 DOCX、ePub 和 PDF。此插件不能独立运行,需要配合 Pandoc 额外程序才可以。
\\nPeriodic Notes - 创建/管理您的每日、每周、每月、季度以及年度笔记。
\\nImage Converter - 快速缩放图片大小。
\\nImage Insert - 从 Unsplash 等获取图片并插入到笔记中。
\\nOmnisearch - 不仅可以搜索文档,还可以搜索 pdf 和图片,如果你有搜索 pdf 和图片的需求很有用。
\\nAdmonition - Obsidian 的块样式,你可以自己定义各种增强块样式,比如警告,笔记,提醒等,由于 Obsidian 0.14 版本内置了 callout 功能,admontion 插件 9(简称 AD 插件) 9.0 以后已经演变成了 callout 辅助工具。
\\nFolder Note - 可以把你的文件夹变成笔记,可以在里面做一些对文件夹的描述或汇总等。
\\n更多插件介绍:Airtable - OB社区插件汇总 - Johnny整理 - 每周更新 - B站 Johnny学
\\n有人喜欢 logseq 的那种工作模式,打开即写,轻记录,obsidian 里也可以开启打开时启动笔记模式,实现 logseq 的打开即写模式,我倒是喜欢目录模式,想要记日记直接快捷键新建日记即可,毕竟我使用的场景,记日记不多,快捷键可以自己设定。
\\n关于写笔记,有人吐槽分类的弊端,每次写作要考虑分类存放,造成负担,我通常用快捷键 ctrl+n 新建笔记,写完了再考虑标题和选择分类,选择分类可以用快捷键也可以用命令等,我是把分类生成一个按钮放到编辑器的顶部,这个功能可以通过 commander 插件实现。这样写作不会被打扰思路,一气呵成,写完再考虑分类,标签什么的,降低分类存放负担。当然你也可以新建个草稿箱,新建文本都放到草稿箱里,我习惯放到根目录,一是明显,强迫自己及时处理,不要积累半成品,二是对有些新建笔记类的插件,剪藏插件等支持良好。
\\n关于分类,有人认为分类没必要,是负担,我深以为然,我认为如果能做到分类和标签通用就好了,就像 WordPress 那样,可以同时选择多个分类,这样类似于标签功能,一个笔记可以属于多个分类,避免纠结分类选择问题。目前还没找到比较好的这方面的插件或者标签能实现类似这种功能,暂且使用目录。我的原则是,你第一眼就想到的,或是第一个想到的它该属于什么分类就放到哪个目录,然后还有其他也沾边的就加标签补充。
\\n关于折腾,有些人喜欢思源那种功能俱全的笔记,避免折腾,沉下心思记笔记(但牺牲了思源笔记存储格式的开放性)。确实是,由于 obsidian 的插件多,很多功能依赖插件实现,就导致刚入门者,不停折腾的现象,这违背了记笔记的初衷。所以建议,不要过于折腾笔记,满足需要即可,核心是记笔记,等实在不好用时,先找第三方插件,都不满足再自己实现。
\\n分享笔记我推荐,Quail 插件,Notion 插件、html server 插件和 Just Share Please,分别适应不同的场景,Just Share Please,如果你有服务器也可以自己搭建分享接口。
\\nWeb Export HTML,这个插件可以生成完整的博客网站,对 obsidian 自定义语法支持粒度良好,如果你打算生成博客推荐这个插件。
\\nQuail 插件的使用可以参考 obsidian分享文章到Quail博客 - 经验分享 - Obsidian 中文论坛
\\n关于剪藏插件也比较多,我推荐 obsidian cliper 和 Markdownload 插件(浏览器插件)。
\\n但,我常用的是简悦插件+shell 脚本,这个是我自己写的脚本监控简悦 markdown 下载文件,然后添加到笔记中,简悦导出的格式比较完整,而且有了 shell 脚本我可以自由的选择添加到哪个目录,非常方便。如果你感兴趣,可以查看 Mac下fswatch+shell实现简悦导出markdown到obsidian - 经验分享 - Obsidian 中文论坛。
\\n灵感记录通常使用 QuickAdd 插件实现,但这种实现方式,通常只能在 obsidian 笔记内使用,我写了一个通过 utools 和 shell 脚本搭配可以在 obsidian 软件外使用的方式,可以参考 uTools和obsidian联动,高效记录您的灵感闪现 - 经验分享 - Obsidian 中文论坛,建议使用最下面更新的版本。
\\n关于同步方案也很多,每种都有自己的优势,我比较了很多种方案,最后选择 RemotelySave+InfiniCloud 的方式,这种方式比较简单而且我认为相对比较安全。详情请查看 RemotelySave+InfiniCloud最简单的多端同步方案实践 - 经验分享 - Obsidian 中文论坛
\\n为什么使用图床?一是,用图床节省笔记本地空间和同步空间,加快同步速度。二是,图床对插件和其他编辑软件的支持良好,对导出其他格式也支持良好。
\\n图床方式有很多种,可以参考我上面对于图片类插件的介绍,我理想中的图床方案是,笔记显示远程图片,但本地要留存一份本地图标,必要时,可以批量替换图片地址,让图片正常显示。甚至可以本地和远程相互切换。国内我认为笔记好的图床方案是 jsdelivr+github,但因 github 有时不稳定,我想到了先推送到 gitee 再通过 gitee 推送到 github 的方案,也写了脚本实现,但由于 obsidian 图片缓存的问题,如果链接替换早了,图片会显示不了,即使远程图片上传完毕,所以,必须图片上传完成之后再替换,但由于 gitee+github 中间环节上传图片的结果无法感知,所以暂时搁浅,或许以后考虑直接上传 github 方案,但这种又不稳定,目前上传 github 的插件经常出现替换图片过早问题。
\\n所以我想,不如图片暂存本地,然后用 TinyPNG 插件压缩,必要时,再直接用 gitt 推送到 github,需要时再替换本地图片为远程图片,目前暂时采用这种方式。
\\nObsidian 中文论坛 - Obsidian 知识管理 笔记
\\n\\n \\n\\n 本作品采用《CC 协议》,转载必须注明作者和本文链接\\n\\n\\n \\n
\\n\\nMacBook够靓够强大,但如果不装上合适的软件,那就是大家吐槽的假苹果,如同车库里停着一辆法拉利却开不出去一样。作为一名科技狂热者和苹果的忠实拥趸,我重视的始终是效率,所以我一直在寻找那些能让我的Mac变得更加强大的软件。
\\n
那现在系好安全带,我要发车了。
\\n
有没有因为不小心删除了关键文件或项目更新出现混乱而感到头疼?Rewind就是你的数字安全网,它是你工作和深夜冒险的个人时间机器。
Rewind在后台默默记录你的屏幕、音频和按键操作,提供了一个为整个Mac设备的神奇撤销按钮。它专为配备M系列芯片的最新Mac设计,确保即使在后台运行时也不会拖慢你的Mac运行速度。你的所有录制数据都只保存在你的Mac上,绝不外泄。得益于Rewind的高压缩率,它能在不占用你存储空间的情况下保存数小时的音频和视频数据。
安全优先:知道一切都被记录下来,让你更加大胆地工作和尝试新事物。
\\n研究宝库:将访谈、网络研讨会等转化为易于搜索的笔记。
\\n找回过去信息:强大的搜索功能让寻找过去的信息变得轻而易举。
\\n
作为一名全栈开发者,敲代码是我的主要工作,但搭建部署环境往往会耗费很多时间,尤其是对于新手来说,可能一次性搞定的几率并不高。这时,ServBay就派上用场了,它用简便的方式解决了部署的难题。
使用ServBay,只需要下载并选择你需要的软件包,剩下的它会帮你搞定,省下了不少宝贵时间。
快速设置:无需花费大量时间来编译源代码或处理依赖关系。它避开了像Homebrew和Docker这类工具的复杂性,同时减少了系统资源的消耗,让开发过程更加顺畅。
\\n便携与灵活:支持多种必备的软件组件,包括Web服务器、PHP、Nodejs、Redis、MariaDB、PostgreSQL等。根据项目需求,我可以自由搭配这些软件组件的不同版本。
\\n即时切换:ServBay让运行不同版本的PHP变得简单,还能即时切换PHP版本,帮助高效调试。
\\n
如果你和我一样,总是在键盘、鼠标和触控板之间切换,那就试试Homerow吧。它就像是你MacBook屏幕上的Spotlight搜索,但用于点击。作为一位打字迅速的人,我的手指可以在键盘上飞快地舞动,但偶尔也需要点击屏幕上的那个小按钮。
Homerow能帮大忙!只需一个快捷键,输入屏幕上几个字母,就能完成点击,让你迅速回到打字状态。而且,Homerow不仅仅是关于点击,它还能帮你快速导航菜单、切换浏览器标签页和打开文件。
提速:减少不必要的手部移动,让你的工作效率飙升。
\\n流畅体验:一旦习惯了使用键盘,你会发现抛弃鼠标其实很自然。
\\n高度可定制:可以根据你的工作流程调整快捷键和操作,这点我特别喜欢。
\\n
作为程序员,我经常会有一些新的点子,感觉自己的大脑像在不断循环播放文章、博客和各种想法,这个时候就可以用到Cubox。它是一个加速版的阅读列表,还加入了一点AI的魔法。想象一下,当你沉浸在研究中,浏览器标签页开了一大堆,而你知道有一个网站包含了关键信息,但稍后想要找到它可就难了。
Cubox此时派上用场。它不仅仅是一个用于保存内容的工具,它是你的个人知识助手。无论是文章、电子邮件、PDF等,它都能快速保存,并自动添加标签、高亮和个人笔记。再也不用担心数字杂乱无章,Cubox就像是一个带AI的图书管理员,能快速提供摘要,帮你找到那句你喜欢的引用。
组织友好:文件夹、标签、高亮等,Cubox应有尽有。满足了我内心对秩序的追求。
\\nAI驱动的洞察:在AI主导的时代,Cubox紧跟潮流。快速摘要和精确搜索结果都得益于AI。
\\n清爽模式:Cubox能将杂乱的网页变为整洁、专注的文本,这真是太神奇了。
\\n
如果你的收件箱像是《黑暗骑士崛起》中的无底洞,充斥着“回复所有人”的噩梦,那么Missive就是你的救星。它把电子邮件变成了一个流畅的、以团队为核心的交流中心,还能整合WhatsApp、Messenger甚至普通短信。
Missive通过标签、标记和强大的搜索功能,让一切井井有条。你可以在邮件线程中分配任务、实时聊天,还能协作编写回复。它是解决“在邮件中迷失”问题的良药。
整理大师:Missive利用标签、标记和出色的搜索功能,保持对话的条理清晰。
\\n结束邮件混乱:可以直接将任务和截止日期分配给邮件,确保不遗漏任何重要事项。
\\n团队和谐:共享草稿减少了误解,使得电子邮件的创建快如闪电。
\\n
想象一下,如果你的工作桌能够根据每项任务、会议或活动自动整理是不是很不可思议?
而这正是Warp为你的Mac工作空间带来的魔法。
\\nWarp不仅仅是关于整理你的应用和窗口,它让你告别了繁琐的窗口管理和应用切换。比如需要同时打开多个浏览器窗口、PDF应用和笔记应用,而且还希望它们并排排开?Warp一键完成。
\\nWarp还能隐藏分散注意力的应用,只留下你需要的,或者通过一个简单的快捷键,隐藏所有打开的窗口、应用和图标。
\\n场景切换:无缝切换工作、研究、娱乐或游戏等不同任务的工作空间。
\\n窗口管理高手:不再需要调整窗口大小或寻找合适的应用——Warp帮你搞定。
\\n提升生产力:为不同的工作模式定制工作空间,让你更快进入状态。
\\n
改变习惯很难。但不妨试试——从这个列表中挑选一个软件,使用一周,看看它是否能给你的工作流程带来新的活力。你可能会对这些独特软件带来的影响感到惊讶。如果你找到了那个成为你新宠的工具,不妨在下面留言分享!
\\n我也很期待听听你的发现!
\\n\\n \\n\\n 本作品采用《CC 协议》,转载必须注明作者和本文链接\\n\\n\\n \\n
我勒个去,才发现上次发的图好多没显示,刚刚重新上传了,感谢各位大佬们捧场 :joy:
\\n时间轮算法的核心在于优化任务调度过程,减少不必要的遍历,提高调度效率。
\\n在传统的任务调度算法中,调度线程可能需要遍历所有任务,检查它们是否到达了执行时间。这种方式在任务数量庞大时效率较低。时间轮算法通过以下方式解决了这一问题:
\\n综上所述,时间轮算法通过将时间分割成刻度,并使用指针移动到对应刻度来触发任务执行,避免了对全部任务的遍历,从而显著提高了调度的效率和性能。这种算法特别适合于中间件和需要处理大量定时任务的场景。
\\n\\n \\n\\n 本作品采用《CC 协议》,转载必须注明作者和本文链接\\n\\n\\n \\n
我用的 sourcetree
\\ngitkraken
\\nGitKraken
\\nvscode 自带git
\\nsublime merge
\\nphpstrom的git,真是好用,如果非要用工具,推荐 sublime merge
\\nphpstorm 自带的就非常好用
\\nphpstorm自带的贼清晰, VSCODE每次都合的一脸懵逼
\\n目前在用 lazygit
\\nsourceTree嘎嘎好用。
\\n\\n\\n中文版本的 git 提交 emoji 提示
\\n
cz-emoji-chinese allows you to easily use emojis in your commits using [commitizen] with chinese.
\\nGlobally
\\nsudo npm i commitizen cz-emoji-chinese -g\\n\\n# Method 1: set as default adapter for your projects\\necho \'{ \\"path\\": \\"cz-emoji-chinese\\" }\' > ~/.czrc\\n\\n# Method 2: If you want minimalist mode, you can set it like this\\necho \'{ \\"path\\": \\"cz-emoji-chinese\\", \\"config\\": { \\"cz-emoji-chinese\\": { \\"skipQuestions\\": [ \\"issues\\", \\"scope\\",\\"body\\" ],\\"subjectMinLength\\": 1 } } }\' > ~/.czrc
\\nLocally
\\nnpm install --save-dev commitizen cz-emoji-chinese
\\nAdd this to your package.json
:
\\"config\\": {\\n \\"commitizen\\": {\\n \\"path\\": \\"./node_modules/cz-emoji-chinese\\"\\n },\\n}
\\n$ git cz
\\nBy default cz-emoji-chinese
comes ready to run out of the box. Uses may vary, so there are a few configuration options to allow fine tuning for project needs.
Configuring cz-emoji-chinese
can be handled in the users home directory (~/.czrc
) for changes to impact all projects or on a per project basis (package.json
). Simply add the config property as shown below to the existing object in either of the locations with your settings for override.
{\\n \\"config\\": {\\n \\"cz-emoji-chinese\\": {}\\n }\\n}
\\nAn array of questions you want to skip:
\\n{\\n \\"config\\": {\\n \\"cz-emoji-chinese\\": {\\n \\"skipQuestions\\": [\\"scope\\", \\"issues\\"]\\n }\\n }\\n}
\\n.czrc like this:
\\n{\\n \\"path\\": \\"cz-emoji-chinese\\",\\n \\"config\\": {\\n \\"cz-emoji-chinese\\": {\\n \\"skipQuestions\\": [\\n \\"issues\\",\\n \\"scope\\"\\n ]\\n }\\n }\\n}
\\nYou can skip the following questions: scope
, body
, and issues
. The type
and subject
questions are mandatory.
By default cz-emoji-chinese
comes preconfigured with the Gitmoji types.
An [Inquirer.js] choices array:
\\n{\\n \\"config\\": {\\n \\"cz-emoji-chinese\\": {\\n \\"types\\": [\\n {\\n \\"emoji\\": \\"🌟\\",\\n \\"code\\": \\":star2:\\",\\n \\"description\\": \\"A new feature\\",\\n \\"name\\": \\"feature\\"\\n }\\n ]\\n }\\n }\\n}
\\nAn [Inquirer.js] choices array:
\\n{\\n \\"config\\": {\\n \\"cz-emoji-chinese\\": {\\n \\"scopes\\": [\\"home\\", \\"accounts\\", \\"ci\\"]\\n }\\n }\\n}
\\nA boolean value that allows for an using a unicode value rather than the default of Gitmoji markup in a commit message. The default for symbol is false.
\\n{\\n \\"config\\": {\\n \\"cz-emoji-chinese\\": {\\n \\"symbol\\": true\\n }\\n }\\n}
\\nAn object that contains overrides of the original questions:
\\n{\\n \\"config\\": {\\n \\"cz-emoji-chinese\\": {\\n \\"questions\\": {\\n \\"body\\": \\"This will be displayed instead of original text\\"\\n }\\n }\\n }\\n}
\\nCommitlint can be set to work with this package by leveraging the package github.com/arvinxx/commitlint-conf....
\\nnpm install --save-dev commitlint-config-gitmoji
\\ncommitlint.config.js
\\nmodule.exports = {\\n extends: [\'gitmoji\'],\\n parserPreset: {\\n parserOpts: {\\n headerPattern: /^(:\\\\w*:)(?:\\\\s)(?:\\\\((.*?)\\\\))?\\\\s((?:.*(?=\\\\())|.*)(?:\\\\(#(\\\\d*)\\\\))?/,\\n headerCorrespondence: [\'type\', \'scope\', \'subject\', \'ticket\']\\n }\\n }\\n}
\\nMIT © Tw93
\\nsubjectMinLength
for Config\\n 本作品采用《CC 协议》,转载必须注明作者和本文链接\\n\\n\\n \\n
Monitor Pro 是一个全面的资源监控工具,旨在帮助你实时跟踪重要的系统指标并提供直观的展现方式。无论你是什么职业,如果你用 VS Code,请不要错过它。
\\n安装后会自动启用该插件。
\\nmarketplace.visualstudio.com/items...
\\n资源监控
\\nCPU 使用率:监控 CPU 利用率的百分比,以了解系统正在利用多少处理能力。
\\nCPU 频率:跟踪当前 CPU 频率,以了解系统如何动态调整其处理能力。
\\nCPU 温度:(如果可以的话)监控温度。
\\n内存使用:关注计算机的内存消耗情况。
\\n网络使用:跟踪机器上的网络活动,包括传入和传出的数据传输速率。
\\n文件系统使用(Linux、macOS):提供磁盘的读写速率。
\\n电池百分比和充电状态:如果你使用的是笔记本电脑或便携设备,此功能可让你监控电池电量和充电状态。
\\n操作系统发行版名称
\\n磁盘使用
\\n排序:自定义监控资源的显示顺序,方便一目了然地监控它们。
\\n刷新间隔:设置更新资源指标的刷新间隔。
\\n无布局移位:确保状态栏中元素的位置和大小不会意外改变。
\\n远程 SSH 资源监控:你可以在远程 SSH 连接的设备上跟踪重要
\\n的系统指标。
\\n高占用率警报:当任何监控的资源达到高占用水平时,接收警报。
\\n仪表板:我希望在一个页面上显示你关心的所有信息,并配备丰富的图表。
\\n我深知监控信息的重要性,所以我的目标是打造一个最全面、最直观的监控工具,让你轻松掌握系统状态。开发 Monitor Pro 的初衷是为了满足大家对系统监控的各种需求。
\\n同时在未来我也希望集成图表的设计,让这些数据更加直观易懂。你可以通过这些图表清楚地看到系统各项指标的变化趋势和相互关系。这样,你就能轻松地了解系统的性能表现。并能够基于这些指标做出明智的决策。
\\n为了在使用 VS Code 的 Remote SSH 时提供一种全面的资源监控工具,以便更好地管理和监控服务器的状态。
\\n详细参考:juejin.cn/post/7284885060338155539
\\n我非常重视用户的反馈和意见,因为它们对于我改进和完善产品至关重要。有好的建议或者遇到了 BUG,请前来反馈:
\\ngithub.com/nexmoe/vscode-monitor-p...
\\n来 Github 点个 star 或是来 VS Code 市场 给个五星好评吧!
\\n\\n \\n \\n支持!看名字像收费版... Monitor-Trail/Monitor-Pro/Monitor-Enterprise :blush:
\\n在使用 docker 搭建镜像时,一般会使用apt-get update && apt-get install -y
命令去安装扩展,但是默认的官方镜像源太慢了,导致根本下载不动。
所以我把这个镜像切换为阿里云的镜像源。
\\n新建一个sources.list
文件,文件内容:
deb https://mirrors.aliyun.com/debian/ bullseye main non-free contrib\\ndeb-src https://mirrors.aliyun.com/debian/ bullseye main non-free contrib\\ndeb https://mirrors.aliyun.com/debian-security/ bullseye-security main\\ndeb-src https://mirrors.aliyun.com/debian-security/ bullseye-security main\\ndeb https://mirrors.aliyun.com/debian/ bullseye-updates main non-free contrib\\ndeb-src https://mirrors.aliyun.com/debian/ bullseye-updates main non-free contrib\\ndeb https://mirrors.aliyun.com/debian/ bullseye-backports main non-free contrib\\ndeb-src https://mirrors.aliyun.com/debian/ bullseye-backports main non-free contrib\\n
\\n\\n将这个文件,复制到/etc/apt/
目录下面,在Dockerfile
文件中在执行RUN apt-get update
前插入
COPY ./sources.list /etc/apt/sources.list\\n\\nRUN apt-get update && apt-get install -y nginx
\\n这样就可以在构建镜像的时候更换apt-get
源了
\\n 本作品采用《CC 协议》,转载必须注明作者和本文链接\\n\\n\\n \\n
helm install rancher rancher-stable/rancher --devel \\\\\\n --namespace cattle-system \\\\\\n --set hostname=rancher.dev.test \\\\\\n --set bootstrapPassword=admin
\\n宿主机配置了hosts
问题解决了 需要安装一下 ingress
\\nalias goland=\\"open -a GoLand\\"
\\n\\n每次都在goland里面,选择打开新项目,然后再去找到项目地址,这样会很麻烦
\\n
命别名后,只需要在命令行运行goland projectname
即可
alias gitworkspace=\\"cd /Users/wanna/work/git/gitworkspace
\\n\\n经常都要cd到某个目录去工作,为什么不直接命个别名呢?
\\n
alias k8s1=\\"kubectl config use-context *** \\"
\\n\\n每次想用哪个环境直接就可以简短运行k8s1后就能切换了
\\n
kl () {\\nkubectl config use-context *** && kubectl logs -f -n test deployment/\\"$1\\"\\n}
\\n\\n想查看projectA的日志只需要运行
\\nkl projectA
即可,不用每次都先去查pods 名称,然后再看日志。这样运行的前提是这个deployment里面只有一个pod,如果有多个,会随机输出其中一个的日志
\\n 本作品采用《CC 协议》,转载必须注明作者和本文链接\\n\\n\\n \\n