Monday, October 18, 2021

V2EX - 技术

V2EX - 技术


有没有办法让系统盘在别的电脑使用

Posted: 18 Oct 2021 04:07 AM PDT

笔记本电脑,一个硬盘,win10 系统,有没有什么办法让这个硬盘拆下来安装到其他电脑或者通过硬盘盒连接到其他电脑,然后通过修改其他电脑的硬盘启动项让其他电脑直接读取这个硬盘,和在原来电脑一样。软件都可以正常使用。我知道有一个 Win to go,但那个好像是会安装一个新系统的,不符合需求。:)

后端 response code 该怎样返回?

Posted: 18 Oct 2021 04:06 AM PDT

前提:前后端定义了通用的数据结构包含 data,mseeage,code,success 这几个基本字段用来去接收后端接口的数据。

场景:某一接口客户端发出的请求出现参数或后端校验等业务错误

问题:后端 http 层的 response code 应该返回什么? 200 还是非 200 ?(呆过的不同公司有着不一样的习惯)

问题来源:主要是用的网络请求框架( retrofit ),对于小于 200 或者大于等于 300 的 response code 直接抛了异常,但我并不想对这异常再进行解析 HttpException 中的 response body 解析出上述的数据结构,所以我拦截了 response 改了 response code 为 200 。这样的话,我对于 response code 无论是什么,我都可以同样的对象解析。

安卓系统 便签/备忘录 哪家强?

Posted: 18 Oct 2021 03:51 AM PDT

便签的话,主要是手机上能比较顺手记录下来 临时想到的东西或者灵感,打开速度必须要快。


还有做一些项目管理和目标管理,要"二次编辑"排粒度比较细的优先级,所以以前果断抛弃滴答清单,和各种清单工具。
只能说清单工具适合加入那种,"今天要做的事"、"要买哪些东西"、"要刷哪个网页"、"五分钟要做的事",清单这种形式比较适合短期的目标管理。
对于"二次编辑",清单的确是不太顺手,不能从大局纵览细粒度对比出哪些是优先做的。


最近在换手机,可以不限于换到各种安卓系统自带的便签。
其实华为云备忘录,挺好用的,能够白嫖云存储,就能在电脑网页上编辑备忘录了。比起很多某象笔记,某道云笔记要轻量,打开速度更快。
垃圾的是没有发现它任何备份和保存快照的能力,哪天服务器抽风,数据就永久全丢了。(抽风基本上是手机硬件厂商的云的通病)


1 稳定性:墙内、能备份不依赖唯一的云
2 启动快:打开和创建速度得快。手机 app 首屏五秒广告肯定慢的
3 互通:安卓和电脑互通
4 尽量是备忘录的形式,一条记录能容下多行文本;最好避免只有"清单"的形式
5 文件夹管理 标签管理
6 无费用或者低费用

WSL 网络突然不可用了,真的是得远离瘟到死

Posted: 18 Oct 2021 03:50 AM PDT

之前一切正常,最近也没有安装啥更新的
突然间今天发现开发工具连不上 WSL 里的 mysql 了,遂进去检查,发现 wsl 里的网络没有了
没有到 Ubuntu 报的是没有网络设备
什么重置网络、重新启用 Linux 子系统,全都试了没用
wsl 也没有 netplan 、networking 什么乱七八糟的东西,网络都是不能配置的,也不能重启相关网络服务
真的不知道怎么操作了

瘟到死真的是

请问,何同学的这个视频都用到了哪些技术?

Posted: 18 Oct 2021 03:49 AM PDT

视频标题:[何同学] 我做了苹果放弃的产品...视频地址: https://www.bilibili.com/video/BV19v411M7Rs?spm_id_from=333.934.0.0 这个触摸屏很酷炫,是如何实现的?谢谢。

请教下单人 solo 开发 app 时的 Java 后端技术选择?

Posted: 18 Oct 2021 03:44 AM PDT

不知道各位全栈老哥开发 app 时,后端接口用的什么语言什么框架?

不考虑微服务什么的特性,只本着这几个目标去:

  • 减少开发工作量
  • 减少服务器资源占用
  • 少折腾

目前看了一些框架,比如 SpringBoot 、Vertx 、Quarkus 、Javalin 、Jfinal 等,也简单调研了 GraphQL 、Apijson,除开 Java,对 Python 的 FastAPI 也做了尝试,始终没有找到完美答案。

老哥们都是怎么搞的?

如何高效掌控 K8s 资源变化? K8s Informer 实现机制浅析

Posted: 18 Oct 2021 03:41 AM PDT

作者

王成,腾讯云研发工程师,Kubernetes contributor,从事数据库产品容器化、资源管控等工作,关注 Kubernetes 、Go 、云原生领域。

概述

进入 K8s 的世界,会发现有很多的 Controller,它们都是为了完成某类资源(如 pod 是通过 DeploymentController, ReplicaSetController 进行管理)的调谐,目标是保持用户期望的状态。

K8s 中有几十种类型的资源,如何能让 K8s 内部以及外部用户方便、高效的获取某类资源的变化,就是本文 Informer 要实现的。本文将从 Reflector(反射器)、DeltaFIFO(增量队列)、Indexer(索引器)、Controller(控制器)、SharedInformer(共享资源通知器)、processorListener(事件监听处理器)、workqueue(事件处理工作队列) 等方面进行解析。

本文及后续相关文章都基于 K8s v1.22

( K8s-informer )

从 Reflector 说起

Reflector 的主要职责是从 apiserver 拉取并持续监听(ListAndWatch) 相关资源类型的增删改(Add/Update/Delete)事件,存储在由 DeltaFIFO 实现的本地缓存(local Store) 中。

首先看一下 Reflector 结构体定义:

// staging/src/k8s.io/client-go/tools/cache/reflector.go type Reflector struct { 	// 通过 file:line 唯一标识的 name 	name string  	// 下面三个为了确认类型 	expectedTypeName string 	expectedType     reflect.Type 	expectedGVK      *schema.GroupVersionKind  	// 存储 interface: 具体由 DeltaFIFO 实现存储 	store Store 	// 用来从 apiserver 拉取全量和增量资源 	listerWatcher ListerWatcher  	// 下面两个用来做失败重试 	backoffManager         wait.BackoffManager 	initConnBackoffManager wait.BackoffManager  	// informer 使用者重新同步的周期 	resyncPeriod time.Duration 	// 判断是否满足可以重新同步的条件 	ShouldResync func() bool 	 	clock clock.Clock 	 	// 是否要进行分页 List 	paginatedResult bool 	 	// 最后同步的资源版本号,以此为依据,watch 只会监听大于此值的资源 	lastSyncResourceVersion string 	// 最后同步的资源版本号是否可用 	isLastSyncResourceVersionUnavailable bool 	// 加把锁控制版本号 	lastSyncResourceVersionMutex sync.RWMutex 	 	// 每页大小 	WatchListPageSize int64 	// watch 失败回调 handler 	watchErrorHandler WatchErrorHandler } 

从结构体定义可以看到,通过指定目标资源类型进行 ListAndWatch,并可进行分页相关设置。

第一次拉取全量资源(目标资源类型) 后通过 syncWith 函数全量替换(Replace) 到 DeltaFIFO queue/items 中,之后通过持续监听 Watch(目标资源类型) 增量事件,并去重更新到 DeltaFIFO queue/items 中,等待被消费。

watch 目标类型通过 Go reflect 反射实现如下:

// staging/src/k8s.io/client-go/tools/cache/reflector.go // watchHandler watches w and keeps *resourceVersion up to date. func (r *Reflector) watchHandler(start time.Time, w watch.Interface, resourceVersion *string, errc chan error, stopCh <-chan struct{}) error {  	... 	if r.expectedType != nil { 		if e, a := r.expectedType, reflect.TypeOf(event.Object); e != a { 			utilruntime.HandleError(fmt.Errorf("%s: expected type %v, but watch event object had type %v", r.name, e, a)) 			continue 		} 	} 	if r.expectedGVK != nil { 		if e, a := *r.expectedGVK, event.Object.GetObjectKind().GroupVersionKind(); e != a { 			utilruntime.HandleError(fmt.Errorf("%s: expected gvk %v, but watch event object had gvk %v", r.name, e, a)) 			continue 		} 	} 	... } 

通过反射确认目标资源类型,所以命名为 Reflector 还是比较贴切的; List/Watch 的目标资源类型在 NewSharedIndexInformer.ListerWatcher 进行了确定,但 Watch 还会在 watchHandler 中再次比较一下目标类型;

认识 DeltaFIFO

还是先看下 DeltaFIFO 结构体定义:

// staging/src/k8s.io/client-go/tools/cache/delta_fifo.go type DeltaFIFO struct { 	// 读写锁、条件变量 	lock sync.RWMutex 	cond sync.Cond  	// kv 存储:objKey1->Deltas[obj1-Added, obj1-Updated...] 	items map[string]Deltas  	// 只存储所有 objKeys 	queue []string  	// 是否已经填充:通过 Replace() 接口将第一批对象放入队列,或者第一次调用增、删、改接口时标记为 true 	populated bool 	// 通过 Replace() 接口将第一批对象放入队列的数量 	initialPopulationCount int  	// keyFunc 用来从某个 obj 中获取其对应的 objKey 	keyFunc KeyFunc  	// 已知对象,其实就是 Indexer 	knownObjects KeyListerGetter  	// 队列是否已经关闭 	closed bool  	// 以 Replaced 类型发送(为了兼容老版本的 Sync) 	emitDeltaTypeReplaced bool } 

DeltaType 可分为以下类型:

// staging/src/k8s.io/client-go/tools/cache/delta_fifo.go type DeltaType string  const ( 	Added   DeltaType = "Added" 	Updated DeltaType = "Updated" 	Deleted DeltaType = "Deleted" 	Replaced DeltaType = "Replaced" // 第一次或重新同步 	Sync DeltaType = "Sync" // 老版本重新同步叫 Sync ) 

通过上面的 Reflector 分析可以知道,DeltaFIFO 的职责是通过队列加锁处理(queueActionLocked)、去重(dedupDeltas)、存储在由 DeltaFIFO 实现的本地缓存(local Store) 中,包括 queue(仅存 objKeys) 和 items(存 objKeys 和对应的 Deltas 增量变化),并通过 Pop 不断消费,通过 Process(item) 处理相关逻辑。

( K8s-DeltaFIFO )

索引 Indexer

上一步 ListAndWatch 到的资源已经存储到 DeltaFIFO 中,接着调用 Pop 从队列进行消费。实际使用中,Process 处理函数由 sharedIndexInformer.HandleDeltas 进行实现。HandleDeltas 函数根据上面不同的 DeltaType 分别进行 Add/Update/Delete,并同时创建、更新、删除对应的索引。

具体索引实现如下:

// staging/src/k8s.io/client-go/tools/cache/index.go // map 索引类型 => 索引函数 type Indexers map[string]IndexFunc  // map 索引类型 => 索引值 map type Indices map[string]Index  // 索引值 map: 由索引函数计算所得索引值(indexedValue) => [objKey1, objKey2...] type Index map[string]sets.String 

索引函数(IndexFunc):就是计算索引的函数,这样允许扩展多种不同的索引计算函数。默认也是最常用的索引函数是:MetaNamespaceIndexFunc

索引值(indexedValue):有些地方叫 indexKey,表示由索引函数(IndexFunc) 计算出来的索引值(如 ns1)。

对象键(objKey):对象 obj 的 唯一 key(如 ns1/pod1),与某个资源对象一一对应。

( K8s-indexer )

可以看到,Indexer 由 ThreadSafeStore 接口集成,最终由 threadSafeMap 实现。

索引函数 IndexFunc(如 MetaNamespaceIndexFunc)、KeyFunc(如 MetaNamespaceKeyFunc) 区别:前者表示如何计算索引,后者表示如何获取对象键(objKey); 索引键(indexKey,有些地方是 indexedValue)、对象键(objKey) 区别:前者表示由索引函数(IndexFunc) 计算出来的索引键(如 ns1),后者则是 obj 的 唯一 key(如 ns1/pod1);

总管家 Controller

Controller 作为核心中枢,集成了上面的组件 Reflector 、DeltaFIFO 、Indexer 、Store,成为连接下游消费者的桥梁。

Controller 由 controller 结构体进行具体实现:

在 K8s 中约定俗成:大写定义的 interface 接口,由对应小写定义的结构体进行实现。

// staging/src/k8s.io/client-go/tools/cache/controller.go type controller struct { 	config         Config 	reflector      *Reflector // 上面已分析的组件 	reflectorMutex sync.RWMutex 	clock          clock.Clock }  type Config struct { 	// 实际由 DeltaFIFO 实现 	Queue  	// 构造 Reflector 需要 	ListerWatcher  	// Pop 出来的 obj 处理函数 	Process ProcessFunc  	// 目标对象类型 	ObjectType runtime.Object  	// 全量重新同步周期 	FullResyncPeriod time.Duration  	// 是否进行重新同步的判断函数 	ShouldResync ShouldResyncFunc  	// 如果为 true,Process() 函数返回 err,则再次入队 re-queue 	RetryOnError bool  	// Watch 返回 err 的回调函数 	WatchErrorHandler WatchErrorHandler  	// Watch 分页大小 	WatchListPageSize int64 } 

Controller 中以 goroutine 协程方式启动 Run 方法,会启动 Reflector 的 ListAndWatch(),用于从 apiserver 拉取全量和监听增量资源,存储到 DeltaFIFO 。接着,启动 processLoop 不断从 DeltaFIFO Pop 进行消费。在 sharedIndexInformer 中 Pop 出来进行处理的函数是 HandleDeltas,一方面维护 Indexer 的 Add/Update/Delete,另一方面调用下游 sharedProcessor 进行 handler 处理。

启动 SharedInformer

SharedInformer 接口由 SharedIndexInformer 进行集成,由 sharedIndexInformer(这里看到了吧,又是大写定义的 interface 接口,由对应小写定义的结构体进行实现) 进行实现。

看一下结构体定义:

// staging/src/k8s.io/client-go/tools/cache/shared_informer.go type SharedIndexInformer interface { 	SharedInformer 	// AddIndexers add indexers to the informer before it starts. 	AddIndexers(indexers Indexers) error 	GetIndexer() Indexer }  type sharedIndexInformer struct { 	indexer    Indexer 	controller Controller  	// 处理函数,将是重点 	processor *sharedProcessor  	// 检测 cache 是否有变化,一把用作调试,默认是关闭的 	cacheMutationDetector MutationDetector  	// 构造 Reflector 需要 	listerWatcher ListerWatcher  	// 目标类型,给 Reflector 判断资源类型 	objectType runtime.Object  	// Reflector 进行重新同步周期 	resyncCheckPeriod time.Duration  	// 如果使用者没有添加 Resync 时间,则使用这个默认的重新同步周期 	defaultEventHandlerResyncPeriod time.Duration 	clock                           clock.Clock  	// 两个 bool 表达了三个状态:controller 启动前、已启动、已停止 	started, stopped bool 	startedLock      sync.Mutex  	// 当 Pop 正在消费队列,此时新增的 listener 需要加锁,防止消费混乱 	blockDeltas sync.Mutex  	// Watch 返回 err 的回调函数 	watchErrorHandler WatchErrorHandler }  type sharedProcessor struct { 	listenersStarted bool 	listenersLock    sync.RWMutex 	listeners        []*processorListener 	syncingListeners []*processorListener // 需要 sync 的 listeners 	clock            clock.Clock 	wg               wait.Group } 

从结构体定义可以看到,通过集成的 controller(上面已分析) 进行 Reflector ListAndWatch,并存储到 DeltaFIFO,并启动 Pop 消费队列,在 sharedIndexInformer 中 Pop 出来进行处理的函数是 HandleDeltas 。

所有的 listeners 通过 sharedIndexInformer.AddEventHandler 加入到 processorListener 数组切片中,并通过判断当前 controller 是否已启动做不同处理如下:

// staging/src/k8s.io/client-go/tools/cache/shared_informer.go func (s *sharedIndexInformer) AddEventHandlerWithResyncPeriod(handler ResourceEventHandler, resyncPeriod time.Duration) { 	...  	// 如果还没有启动,则直接 addListener 加入即可返回 	if !s.started { 		s.processor.addListener(listener) 		return 	}  	// 加锁控制 	s.blockDeltas.Lock() 	defer s.blockDeltas.Unlock()  	s.processor.addListener(listener) 	 	// 遍历所有对象,发送到刚刚新加入的 listener 	for _, item := range s.indexer.List() { 		listener.add(addNotification{newObj: item}) 	} } 

接着,在 HandleDeltas 中,根据 obj 的 Delta 类型(Added/Updated/Deleted/Replaced/Sync) 调用 sharedProcessor.distribute 给所有监听 listeners 处理。

注册 SharedInformerFactory

SharedInformerFactory 作为使用 SharedInformer 的工厂类,提供了高内聚低耦合的工厂类设计模式,其结构体定义如下:

// staging/src/k8s.io/client-go/informers/factory.go type SharedInformerFactory interface { 	internalinterfaces.SharedInformerFactory // 重点内部接口 	ForResource(resource schema.GroupVersionResource) (GenericInformer, error) 	WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool  	Admissionregistration() admissionregistration.Interface 	Internal() apiserverinternal.Interface 	Apps() apps.Interface 	Autoscaling() autoscaling.Interface 	Batch() batch.Interface 	Certificates() certificates.Interface 	Coordination() coordination.Interface 	Core() core.Interface 	Discovery() discovery.Interface 	Events() events.Interface 	Extensions() extensions.Interface 	Flowcontrol() flowcontrol.Interface 	Networking() networking.Interface 	Node() node.Interface 	Policy() policy.Interface 	Rbac() rbac.Interface 	Scheduling() scheduling.Interface 	Storage() storage.Interface }  // staging/src/k8s.io/client-go/informers/internalinterfaces/factory_interfaces.go type SharedInformerFactory interface { 	Start(stopCh <-chan struct{}) // 启动 SharedIndexInformer.Run 	InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer // 目标类型初始化 } 

以 PodInformer 为例,说明使用者如何构建自己的 Informer,PodInformer 定义如下:

// staging/src/k8s.io/client-go/informers/core/v1/pod.go type PodInformer interface { 	Informer() cache.SharedIndexInformer 	Lister() v1.PodLister }  由小写的 podInformer 实现(又看到了吧,大写接口小写实现的 K8s 风格):  type podInformer struct { 	factory          internalinterfaces.SharedInformerFactory 	tweakListOptions internalinterfaces.TweakListOptionsFunc 	namespace        string }  func (f *podInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { 	return NewFilteredPodInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) }  func (f *podInformer) Informer() cache.SharedIndexInformer { 	return f.factory.InformerFor(&corev1.Pod{}, f.defaultInformer) }  func (f *podInformer) Lister() v1.PodLister { 	return v1.NewPodLister(f.Informer().GetIndexer()) } 

由使用者传入目标类型(&corev1.Pod{})、构造函数(defaultInformer),调用 SharedInformerFactory.InformerFor 实现目标 Informer 的注册,然后调用 SharedInformerFactory.Start 进行 Run,就启动了上面分析的 SharedIndexedInformer -> Controller -> Reflector -> DeltaFIFO 流程。

通过使用者自己传入目标类型、构造函数进行 Informer 注册,实现了 SharedInformerFactory 高内聚低耦合的设计模式。

回调 processorListener

所有的 listerners 由 processorListener 实现,分为两组:listeners, syncingListeners,分别遍历所属组全部 listeners,将数据投递到 processorListener 进行处理。

因为各 listeners 设置的 resyncPeriod 可能不一致,所以将没有设置(resyncPeriod = 0) 的归为 listeners 组,将设置了 resyncPeriod 的归到 syncingListeners 组; 如果某个 listener 在多个地方(sharedIndexInformer.resyncCheckPeriod, sharedIndexInformer.AddEventHandlerWithResyncPeriod)都设置了 resyncPeriod,则取最小值 minimumResyncPeriod ;

// staging/src/k8s.io/client-go/tools/cache/shared_informer.go func (p *sharedProcessor) distribute(obj interface{}, sync bool) { 	p.listenersLock.RLock() 	defer p.listenersLock.RUnlock()  	if sync { 		for _, listener := range p.syncingListeners { 			listener.add(obj) 		} 	} else { 		for _, listener := range p.listeners { 			listener.add(obj) 		} 	} } 

从代码可以看到 processorListener 巧妙地使用了两个 channel(addCh, nextCh) 和一个 pendingNotifications(由 slice 实现的滚动 Ring) 进行 buffer 缓冲,默认的 initialBufferSize = 1024 。既做到了高效传递数据,又不阻塞上下游处理,值得学习。

( K8s-processorListener )

workqueue 忙起来

通过上一步 processorListener 回调函数,交给内部 ResourceEventHandler 进行真正的增删改(CUD) 处理,分别调用 OnAdd/OnUpdate/OnDelete 注册函数进行处理。

为了快速处理而不阻塞 processorListener 回调函数,一般使用 workqueue 进行异步化解耦合处理,其实现如下:

( K8s-workqueue )

从图中可以看到,workqueue.RateLimitingInterface 集成了 DelayingInterface,DelayingInterface 集成了 Interface,最终由 rateLimitingType 进行实现,提供了 rateLimit 限速、delay 延时入队(由优先级队列通过小顶堆实现)、queue 队列处理 三大核心能力。

另外,在代码中可看到 K8s 实现了三种 RateLimiter:BucketRateLimiter, ItemExponentialFailureRateLimiter, ItemFastSlowRateLimiter,Controller 默认采用了前两种如下:

// staging/src/k8s.io/client-go/util/workqueue/default_rate_limiters.go func DefaultControllerRateLimiter() RateLimiter { 	return NewMaxOfRateLimiter( 		NewItemExponentialFailureRateLimiter(5*time.Millisecond, 1000*time.Second), 		// 10 qps, 100 bucket size.  This is only for retry speed and its only the overall factor (not per item) 		&BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(10), 100)}, 	) } 

这样,在用户侧可以通过调用 workqueue 相关方法进行灵活的队列处理,比如失败多少次就不再重试,失败了延时入队的时间控制,队列的限速控制(QPS)等,实现非阻塞异步化逻辑处理。

小结

本文通过分析 K8s 中 Reflector(反射器)、DeltaFIFO(增量队列)、Indexer(索引器)、Controller(控制器)、SharedInformer(共享资源通知器)、processorListener(事件监听处理器)、workqueue(事件处理工作队列) 等组件,对 Informer 实现机制进行了解析,通过源码、图文方式说明了相关流程处理,以期更好的理解 K8s Informer 运行流程。

可以看到,K8s 为了实现高效、非阻塞的核心流程,大量采用了 goroutine 协程、channel 通道、queue 队列、index 索引、map 去重等方式;并通过良好的接口设计模式,给使用者开放了很多扩展能力;采用了统一的接口与实现的命名方式等,这些都值得深入学习与借鉴。

PS: 更多内容请关注
k8s-club GitHub 地址: https://github.com/k8s-club/k8s-club

参考资料

[1] Kubernetes 官方文档: [ https://kubernetes.io/ "Kubernetes ]

[2] Kubernetes 源码: [ https://github.com/kubernetes/kubernetes ]

[3] Kubernetes Architectural Roadmap: [ https://github.com/kubernetes/community/blob/master/contributors/design-proposals/architecture/architectural-roadmap.md ]

Windows Insider 过期问题

Posted: 18 Oct 2021 03:31 AM PDT

本人用新 M1 的 Mac 在 PD17 运行 Windows10 的 Insider Preview(23190)时提示了 10 月 31 日过期,但是 Windows Update 也没有其他新的更新,请问有什么办法让这个预览版本一直运行不过期吗?或者要去官网哪里下载新的 ARM 框架的 Preview 版呢?

win11,请问这种图标掉下去有人遇到吗?请问该怎么解决……

Posted: 18 Oct 2021 03:29 AM PDT

iOS15 读取 app「记录 App 活动」文件,展示 app 访问权限及网络记录 app 求 star

Posted: 18 Oct 2021 03:25 AM PDT

读取 app 「记录 App 活动」文件,展示 app 访问权限及网络记录


https://github.com/simon9211/privacyInsight

[疑问] Gitea 和 GItlab 各自的优势是什么?大家更偏向于哪种代码仓库?

Posted: 18 Oct 2021 03:19 AM PDT

公司目前使用的是私有化部署 GitLabCE 打算拿 gitea 再做个仓库备份什么的

关于一对多情况下修改问题

Posted: 18 Oct 2021 02:48 AM PDT

表 1 是作品表

表 2 是类别表

表 3 是 作品和类别的关系表

表 1 和表 2 是一对多的关系

也就是说一个作品可以有多个类别

保存的时候很简单

然后麻烦来了这个修改的时候怎么办呢

我以前用的方法是:修改之前把原来的关系全部删除然后再重新添加 这种方法简单但有一点 那个自增 id 会一直变,想得知诸位是否有更优雅且高效的解决方案?

k8s tomcat 进程 killed 访问 nginx 502 问题

Posted: 18 Oct 2021 02:39 AM PDT

外部 nginx->ingress->service->pod

dockerfile 启动 catalina.sh 就不会生成 catalina.out 问题

所以第一版的 dockerfile 是这样的

第一版会存在可能 tomcat 进程挂了,但是容器没有挂导致流量会正常过来,导致用户访问返回 nginx 502 错误

sh /usr/local/tomcat/bin/startup.sh tee /opt/health.sh <<-'EOF' while true do  if test $( ps -aux | grep java | grep tomcat | wc -l ) -eq 0  then   ps -aux | grep catalina.out | grep -v grep | awk '{print$2}' | xargs kill -9  fi done EOF sh /opt/health.sh & tail -f /usr/local/tomcat/logs/catalina.out  

第二版做了改进,增加了一个脚本去进行健康检查(如果 tomcat 进程挂了就结束 tail 进程)

sh /usr/local/tomcat/bin/startup.sh tee /opt/health.sh <<-'EOF' while true do  if test $( ps -aux | grep java | grep tomcat | wc -l ) -eq 0  then   ps -aux | grep catalina.out | grep -v grep | awk '{print$2}' | xargs kill -9  fi done EOF sh /opt/health.sh & tail -f /usr/local/tomcat/logs/catalina.out 

第二版暂时没发现什么问题,不晓得还有没有其他更简便的方式?

做一个关于程序员学习和求职的小调研

Posted: 18 Oct 2021 02:22 AM PDT

问卷链接: https://wj.qq.com/s2/9172814/76d2/
欢迎参与 ^_^

Debian 11 是默认不带 GUI 了吗,装完之后没有桌面,安装的时候也没看到选择软件的部分

Posted: 18 Oct 2021 02:17 AM PDT

Python 中 有 CAS 的实现吗

Posted: 18 Oct 2021 02:09 AM PDT

Google 了一下 "Python" "CAS",只是搜到了一些关于 GIL 的 ATOMIC 操作。

但是觉得 Python 的 Lock() 又有点沉,有大佬知道有没有类似 CAS 的轻量级实现吗?

Edge 浏览器用高德或百度问什么这么卡

Posted: 18 Oct 2021 12:13 AM PDT

RT,用Chrome什么的就正常,切到Edge就卡的要命。还不是网速加载的事儿,是不是有什么地图加速 API 之类的开关呢?

把开发机升级到了 Fedora 35,然后...

Posted: 17 Oct 2021 10:44 PM PDT

压力一大内核就 oops,看起来磁盘调度器 bfs 有严重问题。

k8s pod 状态 Evicted 怎么进行排查问题?

Posted: 17 Oct 2021 09:33 PM PDT

某个节点上面,某个 pod 重复创建了好多个,然后状态是 Evicted,然后导致节点负载很高

一般来说是磁盘空间,和内存导致的,但是我看了正常

我批量删除这些 Evicted 状态的 pod 之后,节点的负载就降下来了

mysql 迁移到 pgsql 有什么可靠的工具可以推荐一下

Posted: 17 Oct 2021 07:40 PM PDT

接的客户的活,需要将 mysql 迁移到 pgsql,需要可靠性比较高。 市面上有什么成熟的开源工具可以推荐一下吗

react 前端 spa 首页,首次加载一般要优化到几秒,才算合格?

Posted: 17 Oct 2021 07:34 PM PDT

不搞服务端渲染、首页直出。只用常规优化方法,cdn,gzip,js 压缩,懒加载这些。
spa 应用的首页,要优化到首页几秒加载完成才算合格?
(完成标准是指 html 渲染结束即可,不包括页面展示中的大图片、视频这些文件)

Apple 开发者续费遇到问题

Posted: 17 Oct 2021 02:43 PM PDT

去年注册了一个新的国区 Apple ID 并申请了开发者账号,但是当时支付是用美区的 Apple ID 进行订阅付费,今年在续费的时候想换个国区 Apple ID 用来续费,发现没有入口可操作。联系了 Apple 支持,但一直到现在都没有给出明确方案的回复,好像目前没有办法更换付费用的 Apple ID,有遇到同样问题的小伙伴吗?

Linux server 后台有程序在运行的情况下,竟然无法关闭屏幕,救救孩子,阿里嘎多

Posted: 17 Oct 2021 02:41 PM PDT

家里有一台服务器,ubuntu server 没有桌面环境的,然后接了个显示器和键盘,但是一直亮着屏幕感觉不舒服,显示器的位置不好,不想每次都手动关屏幕!就想等一分钟就自动关闭屏幕,然后敲击键盘就打开屏幕

上次问了大佬们也给了方案,执行代码:setterm --blank 1 。但是这个代码只有服务器在闲置的状态才有用,只要服务器在执行任务,就无法息屏,就一直亮着

所以想问一下有没有好办法,在不考虑换硬件的情况下(比如搞个小米智能插座用手机控制电源开关等等),就用代码能不能实现没有键盘输入的时候息屏呢?

大厂内部的前端开发流程有哪些工具链

Posted: 17 Oct 2021 11:21 AM PDT

Golang sync.Map tryLoadOrStore 函数看不懂其中的 ic := i

Posted: 17 Oct 2021 10:45 AM PDT

// tryLoadOrStore atomically loads or stores a value if the entry is not // expunged. // // If the entry is expunged, tryLoadOrStore leaves the entry unchanged and // returns with ok==false. func (e *entry) tryLoadOrStore(i interface{}) (actual interface{}, loaded, ok bool) { 	p := atomic.LoadPointer(&e.p) 	if p == expunged { 		return nil, false, false 	} 	if p != nil { 		return *(*interface{})(p), true, true 	}  	// Copy the interface after the first load to make this method more amenable 	// to escape analysis: if we hit the "load" path or the entry is expunged, we 	// shouldn't bother heap-allocating. 	ic := i 	for { 		if atomic.CompareAndSwapPointer(&e.p, nil, unsafe.Pointer(&ic)) { 			return i, false, true 		} 		p = atomic.LoadPointer(&e.p) 		if p == expunged { 			return nil, false, false 		} 		if p != nil { 			return *(*interface{})(p), true, true 		} 	} } 

为什么不用 ic := i 就会去堆上申请内存呢? 有巨佬或者彦祖知道吗~

整个函数感觉可以直接都放在 for 循环中,为什么要把前两个 if 判断单独拿出来?是因为放在 for 循环外有更好的性能吗

Bitwarden 密码管理器好多网站没有网站图标,大家怎么解决的?

Posted: 17 Oct 2021 06:45 AM PDT

Bitwarden 密码管理器好多网站没有网站图标,资深强迫症患者,很难受,大家怎么解决的呢? 1Password 没有图标的网站更多,但是他可以在 pc 客户端自己编辑添加,虽然编辑添加的图标无法备份,但还是聊胜于无,bitwarden 大部分网站都能取到,偶尔一半个没有怎么搞?

如何把 Debian/Ubuntu 安装到 xfs 文件系统上(或者如何把他们的系统分区变为 xfs)?

Posted: 17 Oct 2021 01:57 AM PDT

是这样的,几天前听说 xfs 文件系统比较耐造,意外断电关机也不会出现无法启动的情况,于是就想在 xfs 文件系统上安装 Debian 。搜索了一圈发现基本上没有说如何在 xfs 文件系统上安装 Debian 的先例。

或者说为什么一旦 Ubuntu 的系统磁盘损坏就会卡在第一屏而不是自动修复(已确认发生的问题只需操作员手动输入相关的修复命令即可恢复)?这个不知道大家有没有什么好的解决方案。

No comments:

Post a Comment