解决KiCAD(系统macOS Big Sur)关联封装(Footprint)报错“No PCB footprint libraries are listed in the current footprint library table.”

最近在把macOS Big Sur系统上的KiCAD5.x升级到6.x之后,新建的项目在进行关联封装操作的时候,报错

具体如下图:

造成这个问题的原因是KiCAD 6.x版本的全局封装库默认存储位置发生了变动,从低版本升级上来,还是会从以前的配置文件中读取原来配置的路径信息,导致找不到新版本的全局封装库路径。

解决方法是删除低版本配置的封装库相关的配置信息即可(删除之前,先关闭KiCAD软件,否则删除无效)。

macOS系统:

Windows系统:

Linux系统:

完成后,重启KiCAD软件即可。

参考链接


[华硕主板] 支持ECC内存的AMD Ryzen™处理器列表

下表列出了支持带ECC功能内存模组的Ryzen™处理器的列表;它们的官方名称;以及是否支持B550X570系列。

请注意,当涉及到APUsRyzen 3000/4000 G系列),只有PRO处理器(例如Ryzen 3 PRO 3200G)支持ECC内存。

官方名称

支持B550系列

支持X570系列

ECC功能

UDIMM ECC

REG ECC

AMD Ryzen™ 5000 Series Processors

V

V

支持

V

 

AMD Ryzen™ 4000 G-Series Processors

V

V

只有PRO支持

V

 

AMD Ryzen™ 3000 Series Processors

V

V

支持

V

 

AMD Ryzen™ 2000 Series Processors

 

V

支持

V

 

AMD Ryzen™ 3000 G-Series Processors

 

V

只有PRO支持

V

 

注意,Ryzen™处理器只支持二手UDIMM ECC,不支持更便宜的二手REG ECC

这个问题简单解释一下,新的REG ECC从性能到价格都是远远高于UDIMM ECC的,但是REG ECC不能用在家用主板上,导致大量淘汰的二手内存需求量不高,因而价格偏便宜。

继续阅读[华硕主板] 支持ECC内存的AMD Ryzen™处理器列表

运维中tcp_tw_recycle net.ipv4.tcp_timestamps引发的坑

NAT环境下,遇到因为tcp_tw_recycle=1和net.ipv4.tcp_timestamps=1引起 Nginx upstream timed out 后,一直没在遇见,今天在朋友的阿里云环境下又重新再一次出现;因此在这炒一次冷饭,让运维新手或者刚上云的朋友大概了解一下,避免再一次采坑。

故障情况:

阿里云账号A的A机房,内网里面部署两台Nginx,通过网络出口(NAT),代理用户访问到阿里云账号B的B机房服务。A机房的Nginx出现:upstream timed out 。

故障的诱因是:net.ipv4.tcp_timestamps=1

抓包图:

注意,这个选项生效的前提是,报文的发出方必须在TCP头部的可选项中增加时间戳字段,否则这个设置是不生效的。

直接上当年的笔记:

先看看TCP IP 对tw的一些解析:
RFC 1323里有这样的定义:

大概的中文意思就是:TCP协议中有一种机制,缓存了每个主机(即ip)过来的连接最新的timestamp值。这个缓存的值可以用于PAWS(Protect Against Wrapped Sequence numbers,是一个简单的防止重复报文的机制)中,来丢弃当前连接中可能的旧的重复报文。而Linux实现这个机制的方法就是同时启用net.ipv4.tcp_timestamps和net.ipv4.tcp_tw_recycle 这两个选项。
这种机制在 客户端-服务器 一对一的时候,没有任何问题,但是当服务器在负载均衡器后面时,由于负载均衡器不会修改包内部的timestamp值,而互联网上的机器又不可能保持时间的一致性,再加上负载均衡是会重复多次使用同一个tcp端口向内部服务器发起连接的,就会导致什么情况呢:

负载均衡通过某个端口向内部的某台服务器发起连接,源地址为负载均衡的内部地址——同一假如恰巧先后两次连接源端口相同,这台服务器先后收到两个包,第一个包的timestamp被服务器保存着,第二个包又来了,一对比,发现第二个包的timestamp比第一个还老——客户端时间不一致。服务器基于PAWS,判断第二个包是重复报文,丢弃之。

反映出来的情况就是在服务器上抓包,发现有SYN包,但服务器就是不回ACK包,因为SYN包已经被丢弃了。为了验证这一结果,可以执行netstat -s | grep timestamp 命令,看输出里面passive connections rejected by timestamp 一项的数字变化。

tcp_ipv4.c中,在接收SYN之前,如果符合如下两个条件,需要检查peer是不是proven,即per-host PAWS检查:

  • 收到的报文有TCP option timestamp时间戳
  • 本机开启了内核参数net.ipv4.tcp_tw_recycle

解决办法:

tcp_tw_recycle=0 或(和)net.ipv4.tcp_timestamps=0同时从4.10内核开始,官方修改了时间戳的生成机制,所以导致 tcp_tw_recycle 和新时间戳机制工作在一起不那么友好,同时 tcp_tw_recycle 帮助也不那么的大。

此处的时间戳并不是我们通常意义上面的绝对时间,而是一个相对时间。很多情况下,我们是没法保证时间戳单调递增的,比如业务服务器之前部署了NAT,LVS等情况。相信很多小伙伴上班的公司大概率实用实用各种公有云,而各种公有云的 LVS 网关都是 FullNAT 。所以可能导致在高并发的情况下,莫名其妙的 TCP 建联不是那么顺畅或者丢连接。

而这也是很多优化文章中并没有提及的一点,大部分文章都是简单的推荐将net.ipv4.tcp_tw_recycle设置为1,却忽略了该选项的局限性,最终造成严重的后果(比如我们之前就遇到过部署在nat后端的业务网站有的用户访问没有问题,但有的用户就是打不开网页)。

参考链接


树莓派固件更新 rpi-update

1 简介

rpi-update是一个用于更新树莓派固件的工具,可以通过apt get install rpi-update来安装

一般来说直接执行下面的命令就可以更新固件(扯淡,基本不可能好吗):

2 跳过自更新

rpi-update启动时会更新自己,如果报以下错误:

可以尝试一下他说的方法来解决:

如果都不行,直接跳过算了,反正也可以用apt来更新这个工具,没必要让他更新自己。

跳过自更新,直接更新固件的方法:

3 【究极方法】本地更新

即使跳过自更新,下载速度也太慢,还经常断流。可以考虑本地更新:

先在PC上下载固件(可以用一下魔法上网):

然后用scp传到树莓派上的/root目录下,之后ssh连上树莓派:

4 检查

对于树莓派4的一个检查方法:

看该目录下是否有libEGL.solibGLESv2.so这两个库,更新前这两个库都是没有的。

如果这两个库出现了,并且是真正的库而不是软链接,就说明更新大概可能也许成功了吧。

参考链接


树莓派固件更新(rpi-update)的那些坑

群晖DSM7通过Docker安装WordPress最新版

PHP 7.x连接MySQL 8.x报错“The server requested authentication method unknown to the client [caching_sha2_password]”

PHP 7.x使用如下代码连接MySQL 8.x

结果出现如下错误信息

原因为 MySQL 支持 caching_sha2_password  / 用户名密码 两种验证方式,但是从 MySQL 8 开始默认使用caching_sha2_password 的验证方式,导致以前版本的客户端不能成功连接。更详细的解释如下:

The server validates the user and returns the connection status. MySQL uses caching_sha2_password and auth_socket plugins for validation.

The caching_sha2_password plugin uses an SHA-2 algorithm with 256-bit password encryption. MySQL 8 prefers this auth method.

Whereas the auth_socket plugin checks if the socket username matches with the MySQL username. If the names don’t match, it checks for the socket username of the mysql.user. If a match is found, the plugin permits the connection.

But to serve the pre 8.0 clients and avoid compatibility errors, it is preferred to revert back the auth method. Older versions of MySQL use mysql_native_password plugin for validation.

解决方案为修改用户默认的认证方式,如下:

参考链接


[RESOLVED] MySQL the server requested authentication method unknown to the client

macOS Monterey (12.0.1)解决App Store无法下载APP的问题

最近,公司的一台电脑升级到 macOS Monterey (12.0.1),之后从进行软件更新,以及 XCode 的下载安装。由于网速的限制,临时把 XCode 的下载进行了暂停操作,之后忘记恢复就进行了重启。

结果第二天在App的安装界面上就看不到被暂停的任务了。然后在 App Store 中尝试继续进行下载,发现无法进行下载任务,下载按钮点击之后,状态一闪而过,又回到待下载状态。

更换账号/重启应用/重启系统之后,无法解决问题。

应该是 App Store 内部状态混乱了,导致无法进行下载任务,需要对 App Store 进行重置操作。

网上搜索很久,才找到解决方案,执行如下命令:

之后重启系统,重新点击下载应用,即可解决问题。

参考链接


群晖DSM7通过Docker安装MySQL最新版(8.x)

搜索并下载镜像,如下:

注意:此处搜索MySQL,会出现两个MySQL镜像,很容易让人不知道该如何选择。其实这两个镜像一个是社区维护,一个是Oracle维护的版本。两者对于普通用户来说,差别不大,选择任意一个都可以。这里,我们选择社区维护的版本。

配置必要的参数信息:

存储位置配置如下:

存储位置(/var/lib/mysql)是镜像中MySQL的默认数据存储目录,位置(/etc/mysql/conf.d)是镜像中MySQL的配置文件目录,这两个目录位置不要变更,如果需要修改配置,则在主机的对应目录上进行调整。

MySQL 服务启动时会以 /etc/mysql/my.cnf 为配置文件,之后会导入 /etc/mysql/conf.d 目录中所有以 .cnf 为后缀的文件。这些文件会拓展或覆盖 /etc/mysql/my.cnf 文件中的配置。

因此可以在挂载至 MySQL 容器中的 /etc/mysql/conf.d 目录创建需要的配置文件。

比如如下:

对于MySQL的日志目录,需要进行特殊授权,否则没办法启动成功。

权限授权方式如下:

配置MySQL的默认登陆密码:

MYSQL_ROOT_PASSWORD 为手工添加,其它是安装 MySQL 自带的。MYSQL_ROOT_PASSWORD 用于设置 root 的密码。

查看系统运行状态:

设置登录的SHELL

如果想替换掉群晖自带的MariaDB,实现主从同步,可以参考家里ADSL上网无固定外网IP的群晖NAS安全实现与公网MySQL服务器主从同步

默认Docker创建出来的MySQL是外部网络都可以访问的,这样不安全,我们可以通过群晖自带的防火墙禁止特定的端口访问来阻止外部IP的访问请求。

操作步骤如下:

参考链接


从Vue 2到Vue 3组织代码的思维转变

到了Vue 3,当我们看完组合式 API相关文档,蠢蠢欲动立马上手把业务代码挪到setup内时,竟发现无法在setup()内部通过 this 获取当前组件实例了(this 是 undefined)!

其实想要变相获取“this”可以用 getCurrentInstance ,比如像这样访问全局属性:

真正属于组件的内容是ctxproxyproxy就是对ctx包装了一层 Proxy。目前看来属实没用,就不展开来说了。

getCurrentInstance 只能setup生命周期钩子中调用。不仅使用起来麻烦,且只适用于开发环境。官方都告知我们日常开发中不要用:

貌似到头来this的问题还是无解。Vue 3 Composition API 的设计初衷也是为了减少对组件实例的依赖,避免this指向的困扰。包括一些全局方法也可以提取到 composables 组合函数中,无需再通过当前组件的原型链获得。我们动不动就通过this获取组件实例的思想该转变了

怎么个直接使用法?我们先看一眼简易版 选项式 API组合式 API 的对比。再用例子来捋:

API 对比

1. 读写数据

Vue 2的做法,或者说Option API更准确 (后面就简写成Vue 2)

data中定义,this.xxx获取
<template>模版中不需要用this

Vue 3 的 Composition API (后面就简写成 Vue 3)

ref reactive定义。
通过ref方法定义的属性在 setup 函数内需要通过.value去访问它的值 (template 模版内不用), reactive则不用。我们可以简单地把 ref(obj) 理解为 reactive({ value: obj })
详细请看 ➡️ 【Vue 3 之:弄清 ref reactive toRef toRefs】

如何选择 refreactive?建议:

  1. 基础类型值(StringNumberBoolean等) 或单值对象(类似{ count: 3 }这样只有一个属性值的对象) 使用 ref
  2. 引用类型值(ObjectArray)使用 reactive
  3. 对于 ref 对象可以使用 unref 语法糖来免去.value访问的困扰

2. 定义/调用方法

Vue 2:methods

继续上面的例子,我们把请求列表数据的操作提取成一个方法。(略去重复的代码)

Vue 3

3. 获取模版DOM元素/或组件实例的引用

Vue 2

直接整上 element-plus Form 表单 的的例子,<el-form>是我们写的DemoForm组件的一个子组件,通过为它添加一个refattribute,就能使用使用this.$refs[ref值]直接访问子组件以及它的所有属性/方法了。
这边只放相对实际的场景用例,给 DOM 元素添加 ref 引用的例子看这里:【模板引用】

Vue 3

我们来修改成 Composition API 版本:
别忘了 ref 创建的变量要用.value获取值
详细文档请阅:【在组合式 API 中使用 template refs】

4. 父组件向子组件传值

文档:Props
使用 DOM 模板时,camelCase (驼峰命名法) 的 props 需要使用等价的 kebab-case (短横线分隔命名) 命名。

说明:第 4-8 点 都会结合同一个 Tabs 标签页的例子,循序渐进梳理这几个属性或方法。依然用了element-plus 的组件(TabsTabPane)。

Vue 2

父组件:📃src/views/design/indexV2.vue

子组件 DesignTabs:📃src/views/design/components/DesignTabsV2.vue

Vue 3

转化成 Composition API 后的子组件:(一贯省略重复代码)
📃src/views/design/components/DesignTabsV3.vue

5. 计算属性computed

比如我们现在希望在点击 tab 标签的时候能获得 tab 的序号(index):

Vue 2

组件 DesignTabs:📃src/views/design/components/DesignTabsV2.vue

Vue 3

这里就比较不一样了,props 的值是不允许在子组件直接修改的。子组件的activeName状态初始值为传入的activeTab,如果activeTabtabOptions一样通过 toRefstoRef 包装,那么activeName的修改是和activeTab深度响应的,这样会报错;
如果要同步修改父组件的值,可以通过emit事件(后面会说)

组件 DesignTabs:📃src/views/design/components/DesignTabsV3.vue

这里想额外提一嘴computed可以包在reactive内使用,在组件数据比较简单的情况下甚至可以直接用reactive包起组件全部数据,就好像 Option Api 的 data 选项那样。这样做的目的是在setup()访问不用再带上.value
但这同时会带来一个问题,在模版需要使用state.xx去渲染,而且如果我们 return 的时候把state解构,包含的状态会失去响应性,那就得不偿失了。需要用toRefs包裹再传递,即可维持其响应性。

6. 侦听器watch

获取这个tabIndex有什么用呢,目的是在当前标签变化时根据index刷新对应TabPane的子组件的数据。但是如果在标签点击事件触发数据刷新也不合适,因为我们不希望重复点击相同tab时也去刷新。那么这个时候watch或者watchEffect就登场了。

Vue 2

组件 DesignTabs:📃src/views/design/components/DesignTabsV2.vue

Vue 3

这个写法可能不是很直观,可以看下 ➡️ 组合式 API 模板引用在 v-for 中的用法
组件 DesignTabs:📃src/views/design/components/DesignTabsV3.vue

watchwatchEffect 的功能是等效的,都是侦听其依赖,并在依赖值变更时重新运行定义的函数。两者区别:

watch

  • 必须在第一个参数明确指定跟踪的依赖
    侦听器数据源只能是getter/effect函数、refreactive对象,或者包含这些类型(的数据)的数组
    换句话说,只要侦听数据不是refreactive对象,就必须传入一个箭头函数
    打个比方,若要侦听reactive对象的某个属性(例:const state = reactive({ count: 0 })count),便不能像侦听单个ref或整个reactive对象那样直接传一个变量,而是必须在第一个参数传入一个回调函数,如() => state.count
  • 第二个参数是依赖值变更时执行的回调,函数内能访问被侦听状态的当前值和前一个值;
  • 组件初始化时不会执行回调。如果需要可在第三个参数(Object)中设置immediate: true
  • 如果要对多层嵌套状态深度侦听,在第三个参数中设置deep: true

watchEffect

  • 无需手动传入依赖项;
  • 只有一个参数,即侦听数据变更的回调函数,会自动跟踪所有函数中用到的变量;
  • 组件初始化时即会执行一次。

7. 子组件向父组件通信(触发父组件方法)

Vue 2

父组件:📃src/views/design/indexV2.vue

子组件 DesignTabs:📃src/views/design/components/DesignTabsV2.vue

Vue 3

子组件 DesignTabs:📃src/views/design/components/DesignTabsV3.vue

8. 使用 Vue Router

Vue 2

📃src/views/design/components/DesignTabsV2.vue

Vue 3

📃src/views/design/components/DesignTabsV3.vue

9. 获取 Vuex 对象

Vue 2

Vue 3

参考链接


从 Vue 2 到 Vue 3 组织代码的思维转变(一)- 获取组件实例