1. 90 后是不是玩不动游戏了?
日常工作 MaMacBook Apple M2 Max
大约 2018 年买的外星人 R7 日常 Windows 挂机
前几天通过 steam 下载了战神 4 卡的不行
索性就组个好点的机器吧
退款原因 玩了一次战神 4 特效全开没有现象中好 ,突然就有了个想法 为什么不买个 ps5 才$500 !
买完 ps5 玩一次就退货了
玩不动了 不想玩了
是不是这一代人 都是有我这样想法吗
15 篇热帖
2023 年 6 月 销量中 Model 3 22741 在同款中排第二。
周围的人总是问我,为啥特斯拉卖的这么好? 有没有大佬说一下,为啥呢
是的,你没看错,是一个人做一个低代码平台。
一人肝了好几年了,基本思路:
1 、前端可视化拖拽,逻辑编排+脚本支持,react 实现
该部分前端已发布一个开源项目: https://github.com/codebdy/rxdrag
2 、后端基于微内核(或者微服务),UML 类图转 Grahpql 接口。
通过微服务扩展复杂逻辑或者基础设施,通过脚本跟逻辑编排扩展业务逻辑。
该部分基本流程已经跑通,代码开源( golang+mysql )
相关文章:
实践,制作一个高扩展、可视化低代码前端,详实、完整(掘金)
实践,制作一个高扩展、可视化低代码前端,详实、完整(知乎)
挑战零代码:可视化逻辑编排(知乎)
挑战零代码:可视化逻辑编排(掘金)
目标:
做一个低代码平台,取名乐搭( Leda )。
目前整个项目组,只有一个人,有机会吗?
arxiv 2307.12037
arxiv 2307.12008
看制备环境基本等于手搓(高中化学实验室即可)
https://sciencecast.org/casts/suc384jly50n
不懂,来大佬解读一下
Higress 是基于阿里巴巴内部两年多的 Envoy Gateway 实践沉淀,以开源 Istio 与 Envoy 为核心构建的下一代云原生网关。Higress 实现了安全防护网关、流量网关、微服务网关三层网关合一,可以显著降低网关的部署和运维成本。
官网地址: https://higress.cn
GitHub 地址: https://github.com/alibaba/higress
Higress 作为云原生网关的核心优势如下:
“云原生”已经不再是一个新鲜词,但企业对云原生技术的学习使用成本仍有许多顾虑,对云原生新标准的追赶又有很多焦虑;
Higress 同时提供了本地安装/生产部署的 quickstart ,可以一键部署,并通过控制台操作快速上手;基于简单易用的控制台,Higress 可以封装 Ingress/Gateway API 的标准细节,根治技术追赶焦虑。
K8s 带来了云原生的路由标准 Ingress/Gateway API ,如同 POSIX 定义 Unix 可移植操作系统标准,历时 35 年经久不衰,云原生的路由标准的生命周期一定会远超过 K8s 本身;
Higress 结合阿里内部实践以及阿里云产品沉淀,积累了基于 Ingress API 的丰富的路由策略扩展能力,同时还兼容大部分 Nginx Ingress 能力,这些能力后续也将在 Gateway API 上支持。
企业内有大量传统架构部署的服务,会成为向云原生架构演进的技术负担,要求云原生网关具备对接异构服务架构的能力;
基于 Higress 提供的多种服务发现机制,网关路由不仅可以转发到 K8s 服务,也可以直接配置 IP 转发到到物理机上的服务;基于 Nacos/ZooKeeper 等注册中心对接,还可以轻松实现 Spring Cloud 和 Dubbo 微服务的路由,无论其是否部署在 K8s 内。
基于扩展机制进行二次开发的能力,是云原生网关在不同业务场景下都能适配落地的关键;
Higress 提供了灵活的插件扩展机制,目前插件市场已经推出多个官方插件,并支持用户通过控制台直接上传自己开发的插件,同时开源社区的插件市场生态也在不断建设中。
传统 Nginx 更新规则需要 reload 会导致链接抖动,导致流量损失,对实时通信、视频、IOT 无法容忍;
对于路由规则,Wasm 插件逻辑更新,以及证书改动等等,Higress 全部支持热更新,不会造成任何连接抖动。
下文将介绍 Higress 全局配置控制面实现机制,Higress 数据面基于 Envoy 是 C++ 语言开发,控制面则是基于 Go 语言开发。控制面的开发上手门槛还是很低的,欢迎有更多同学参与贡献。社区也有多个学习兴趣小组,欢迎加入学习: https://github.com/alibaba/higress/issues?q=is%3Aopen+is%3Aissue+label%3A%22learning+to+share%22
Higress 有个全局配置 ConfigMap 对象 higress-config ,参考配置如下:
apiVersion: v1
data:
higress: |-
tracing:
enable: true
sampling: 100
timeout: 500
skywalking:
service: skywalking-oap-server.op-system.svc.cluster.local
port: 11800
...
...
kind: ConfigMap
metadata:
name: higress-config
namespace: higress-system
具体配置说明请参考 Higress 全局配置说明文档, 本文介绍以 Tracing 为例,详细说明 Tracing 全局配置是如何转成 EnvoyFilter 和如何同时实现实时下发到 Higress Gateway 过程。
本文涉及整体架构流程、初始化过程和启动、higress-config 变更和处理流程、通知 XDSUpdater 、构建 EnvoyFilter 和下发以及如何扩展全局配置等内容。

IngressConfig 是 Higress 一个核心结构体, 负责监控 Ingress ,McpBridge, Http2Rpc, WasmPlugin 等 k8s 资源, 同时集成 ConfigStore Interface ,通过 List 接口下发 VirtualService, DestinationRule, EnvoyFilter, ServiceEntry, WasmPlugin 等 CR 资源。
ConfigmapMgr 结构体负责整个核心流程,包括通过 Informer List/Watch 机制监控 higress-config 的变更,同时遍历 ItemControllers 下发变更通知,提供构建 EnvoyFilter 列表等功能。
TracingController 结构体负责具体的 Tracing 数据校验,构建 Tracing EnvoyFilter, 以及通过 ItemEventHandler 下发变更通知等。
HigressConfig 是 higress-config Configmap 所对应数据的结构体。
初始化过程入口在 NewIngressConfig , 初始化 IngressConfig 时同时构建 HigressConfigController 和 ConfigmapMgr 。
// pkg/ingress/config/ingress_config.go
func NewIngressConfig(localKubeClient kube.Client, XDSUpdater model.XDSUpdater, namespace, clusterId string) *IngressConfig {
// ...
// 构建 controller 和 configmapMgr
higressConfigController := configmap.NewController(localKubeClient, clusterId, namespace)
config.configmapMgr = configmap.NewConfigmapMgr(XDSUpdater, namespace, higressConfigController, higressConfigController.Lister())
return config
}
通过 Higress 提供 NewCommonController 初始化 HigressConfigController 用于监听 higress-system 命名空间下 Configmap 的变化。
// pkg/ingress/kube/configmap/controller.go
type HigressConfigController controller.Controller[listersv1.ConfigMapNamespaceLister]
func NewController(client kubeclient.Client, clusterId string, namespace string) HigressConfigController {
informer := client.KubeInformer().Core().V1().ConfigMaps().Informer()
return controller.NewCommonController("higressConfig", client.KubeInformer().Core().V1().ConfigMaps().Lister().ConfigMaps(namespace),
informer, GetConfigmap, clusterId)
}
func GetConfigmap(lister listersv1.ConfigMapNamespaceLister, namespacedName types.NamespacedName) (controllers.Object, error) {
return lister.Get(namespacedName.Name)
}
ConfigmapMgr 初始化具体步骤如下:
// pkg/ingress/kube/configmap/controller.go
func NewConfigmapMgr(XDSUpdater model.XDSUpdater, namespace string, higressConfigController HigressConfigController, higressConfigLister listersv1.ConfigMapNamespaceLister) *ConfigmapMgr {
// 构建 ConfigmapMgr
configmapMgr := &ConfigmapMgr{
XDSUpdater: XDSUpdater,
Namespace: namespace,
HigressConfigController: higressConfigController,
HigressConfigLister: higressConfigLister,
higressConfig: atomic.Value{},
}
// 设置 HigressConfigController configmap 新增或者更新回调函数 configmapMgr.AddOrUpdateHigressConfig
configmapMgr.HigressConfigController.AddEventHandler(configmapMgr.AddOrUpdateHigressConfig)
// 设置 HigressConfig 结构体默认值
configmapMgr.SetHigressConfig(NewDefaultHigressConfig())
// 初始化 TracingController
tracingController := NewTracingController(namespace)
// 把 tracingController 添加到 configmapMgr itemControllers 里
configmapMgr.AddItemControllers(tracingController)
// 初始化 itemEventHandler , 同时遍历 itemControllers ,设置 itemEventHandler
configmapMgr.initEventHandlers()
// 返回 configmapMgr
return configmapMgr
}
在 IngressConfig 添加 HigressConfigController Run() 和 HasSynced() 控制流程。
// pkg/ingress/config/ingress_config.go
func (m *IngressConfig) Run(stop <-chan struct{}) {
// ...
// 启动 HigressConfigController
go m.configmapMgr.HigressConfigController.Run(stop)
}
func (m *IngressConfig) HasSynced() bool {
// ....
if !m.configmapMgr.HigressConfigController.HasSynced() {
return false
}
}
ConfigmapMgr 通过收到 HigressConfigController 通知来处理变更请求。
具体变更流程如下:
// pkg/ingress/kube/configmap/controller.go
func (c *ConfigmapMgr) AddOrUpdateHigressConfig(name util.ClusterNamespacedName) {
// 只监听 higress-system 命名空间下 name 为 higress-config Configmap 的变化
if name.Namespace != c.Namespace || name.Name != HigressConfigMapName {
return
}
// ...
// 获取 higress-config 内容
higressConfigmap, err := c.HigressConfigLister.Get(HigressConfigMapName)
// 通过 yaml.Unmarshal 转成 HigressConfig
newHigressConfig := NewDefaultHigressConfig()
if err = yaml.Unmarshal([]byte(higressConfigmap.Data[HigressConfigMapKey]), newHigressConfig); err != nil {
IngressLog.Errorf("data:%s, convert to higress config error, error: %+v", higressConfigmap.Data[HigressConfigMapKey], err)
return
}
// ...
// 遍历 ItemControllers, 校验配置是否合法
for _, itemController := range c.ItemControllers {
if itemErr := itemController.ValidHigressConfig(newHigressConfig); itemErr != nil {
IngressLog.Errorf("configmap %s controller valid higress config error, error: %+v", itemController.GetName(), itemErr)
return
}
}
// 和上次比对这次数据是否有变更
oldHigressConfig := c.GetHigressConfig()
result, _ := c.CompareHigressConfig(oldHigressConfig, newHigressConfig)
// ...
// 如果数据有变更,就遍历 ItemControllers 通知每个 itemController 数据有变更,同时保存这次变更到本地。
if result == ResultReplace || result == ResultDelete {
for _, itemController := range c.ItemControllers {
IngressLog.Infof("configmap %s controller AddOrUpdateHigressConfig", itemController.GetName())
if itemErr := itemController.AddOrUpdateHigressConfig(name, oldHigressConfig, newHigressConfig); itemErr != nil {
IngressLog.Errorf("configmap %s controller AddOrUpdateHigressConfig error, error: %+v", itemController.GetName(), itemErr)
}
}
// 保存这次变更
c.SetHigressConfig(newHigressConfig)
}
}
TracingController 变更处理就比较简单:
// pkg/ingress/kube/configmap/tracing.go
func (t *TracingController) AddOrUpdateHigressConfig(name util.ClusterNamespacedName, old *HigressConfig, new *HigressConfig) error {
// ...
// 检查 Tracing 部分数据是否有变更
result, _ := compareTracing(old.Tracing, new.Tracing)
// 如果有变更,DeepCopy 一份 Tracing 数据保存到本地,同时通过 eventHandler 下发变更通知
switch result {
case ResultReplace:
if newTracing, err := deepCopyTracing(new.Tracing); err != nil {
IngressLog.Infof("tracing deepcopy error:%v", err)
} else {
t.SetTracing(newTracing)
IngressLog.Infof("AddOrUpdate Higress config tracing")
t.eventHandler(higressTracingEnvoyFilterName)
IngressLog.Infof("send event with filter name:%s", higressTracingEnvoyFilterName)
}
case ResultDelete:
t.SetTracing(NewDefaultTracing())
IngressLog.Infof("Delete Higress config tracing")
t.eventHandler(higressTracingEnvoyFilterName)
IngressLog.Infof("send event with filter name:%s", higressTracingEnvoyFilterName)
}
return nil
}
在 ConfigmapMgr 初始化时候调用 configmapMgr.initEventHandlers(), 这个 func 会创建 ItemEventHandler, 同时遍历 ItemControllers 设置 ItemEventHandler 。
// pkg/ingress/kube/configmap/config.go
type ItemEventHandler = func(name string)
// pkg/ingress/kube/configmap/controller.go
func (c *ConfigmapMgr) initEventHandlers() error {
itemEventHandler := func(name string) {
c.XDSUpdater.ConfigUpdate(&model.PushRequest{
Full: true,
ConfigsUpdated: map[model.ConfigKey]struct{}{{
Kind: gvk.EnvoyFilter,
Name: name,
Namespace: c.Namespace,
}: {}},
Reason: []model.TriggerReason{ModelUpdatedReason},
})
}
for _, itemController := range c.ItemControllers {
itemController.RegisterItemEventHandler(itemEventHandler)
}
return nil
}
这里 XDSUpdater 是从 IngressConfig 初始化传入,XDSUpdater.ConfigUpdate() 用于更新通知下发。
进一步跟踪可以发现在 Higress controller server 启动时执行 s.initXdsServer 函数创建 s.xdsServer ,具体逻辑不在本文讨论范围, 有兴趣可以进一步阅读源码。
// pkg/bootstrap/server.go
func NewServer(args *ServerArgs) (*Server, error) {
// ...
s := &Server{
ServerArgs: args,
httpMux: http.NewServeMux(),
environment: e,
readinessProbes: make(map[string]readinessProbe),
server: server.New(),
}
s.environment.Watcher = mesh.NewFixedWatcher(&v1alpha1.MeshConfig{})
s.environment.Init()
initFuncList := []func() error{
s.initKubeClient,
s.initXdsServer,
s.initHttpServer,
s.initConfigController,
s.initRegistryEventHandlers,
s.initAuthenticators,
}
for _, f := range initFuncList {
if err := f(); err != nil {
return nil, err
}
}
// ...
return s, nil
}
// pkg/bootstrap/server.go
func (s *Server) initXdsServer() error {
log.Info("init xds server")
s.xdsServer = xds.NewDiscoveryServer(s.environment, nil, PodName, PodNamespace, s.RegistryOptions.KubeOptions.ClusterAliases)
// ...
return s.initGrpcServer()
}
IngressConfig List 用于 VirtualService, DestinationRule, EnvoyFilter, ServiceEntry, WasmPlugin 等 CR 资源下发, 这里主要关注 EnvoyFilter CR 资源下发。
// pkg/ingress/config/ingress_config.go
func (m *IngressConfig) List(typ config.GroupVersionKind, namespace string) ([]config.Config, error) {
if typ != gvk.Gateway &&
typ != gvk.VirtualService &&
typ != gvk.DestinationRule &&
typ != gvk.EnvoyFilter &&
typ != gvk.ServiceEntry &&
typ != gvk.WasmPlugin {
return nil, common.ErrUnsupportedOp
}
// ...
if typ == gvk.EnvoyFilter {
m.mutex.RLock()
defer m.mutex.RUnlock()
var envoyFilters []config.Config
// 调用 ConfigmapMgr ConstructEnvoyFilters 获取需要下发 EnvoyFilter 列表
configmapEnvoyFilters, err := m.configmapMgr.ConstructEnvoyFilters()
if err != nil {
IngressLog.Errorf("Construct configmap EnvoyFilters error %v", err)
} else {
for _, envoyFilter := range configmapEnvoyFilters {
envoyFilters = append(envoyFilters, *envoyFilter)
}
IngressLog.Infof("Append %d configmap EnvoyFilters", len(configmapEnvoyFilters))
}
if len(envoyFilters) == 0 {
IngressLog.Infof("resource type %s, configs number %d", typ, len(m.cachedEnvoyFilters))
return m.cachedEnvoyFilters, nil
}
// 需要下发 configmap EnvoyFilter 列表 和 m.cachedEnvoyFilters 列表聚合一下下发
envoyFilters = append(envoyFilters, m.cachedEnvoyFilters...)
IngressLog.Infof("resource type %s, configs number %d", typ, len(envoyFilters))
return envoyFilters, nil
}
}
调用 ConfigmapMgr ConstructEnvoyFilters 获取需要下发 EnvoyFilter 列表, 同时和 m.cachedEnvoyFilters 列表聚合一下再下发。
这里 m.cachedEnvoyFilters 是在构建 VirtualService 时生成,有兴趣可以进一步阅读 IngressConfig 源码。
这里比较简单,遍历一下 ItemControllers ,聚合每个 itemController 返回的 EnvoyFilters.
// /pkg/ingress/kube/configmap/controller.go
func (c *ConfigmapMgr) ConstructEnvoyFilters() ([]*config.Config, error) {
configs := make([]*config.Config, 0)
for _, itemController := range c.ItemControllers {
IngressLog.Infof("controller %s ConstructEnvoyFilters", itemController.GetName())
if itemConfigs, err := itemController.ConstructEnvoyFilters(); err != nil {
IngressLog.Errorf("controller %s ConstructEnvoyFilters error, error: %+v", itemController.GetName(), err)
} else {
configs = append(configs, itemConfigs...)
}
}
return configs, nil
}
这里就比较简单,根据保存的 Tracing 数据构建对应的 EnvoyFilter
// pkg/ingress/kube/configmap/tracing.go
func (t *TracingController) ConstructEnvoyFilters() ([]*config.Config, error) {
// ...
tracingConfig := t.constructTracingTracer(tracing, namespace)
if len(tracingConfig) == 0 {
return configs, nil
}
config := &config.Config{
Meta: config.Meta{
GroupVersionKind: gvk.EnvoyFilter,
Name: higressTracingEnvoyFilterName,
Namespace: namespace,
},
Spec: &networking.EnvoyFilter{
ConfigPatches: []*networking.EnvoyFilter_EnvoyConfigObjectPatch{
{
ApplyTo: networking.EnvoyFilter_NETWORK_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_GATEWAY,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: "envoy.filters.network.http_connection_manager",
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: util.BuildPatchStruct(tracingConfig),
},
},
{
ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_GATEWAY,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: "envoy.filters.network.http_connection_manager",
SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{
Name: "envoy.filters.http.router",
},
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: util.BuildPatchStruct(`{
"name":"envoy.filters.http.router",
"typed_config":{
"@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router",
"start_child_span": true
}
}`),
},
},
},
},
}
configs = append(configs, config)
return configs, nil
}
type HigressConfig struct {
Tracing *Tracing `json:"tracing,omitempty"`
// 在这里添加对应的数据结构来扩展配置
}
// pkg/ingress/kube/configmap/config.go
func NewDefaultHigressConfig() *HigressConfig {
higressConfig := &HigressConfig{
Tracing: NewDefaultTracing(),
// 在这里增加扩展配置默认值
}
return higressConfig
}
type ItemController interface {
GetName() string
AddOrUpdateHigressConfig(name util.ClusterNamespacedName, old *HigressConfig, new *HigressConfig) error
ValidHigressConfig(higressConfig *HigressConfig) error
ConstructEnvoyFilters() ([]*config.Config, error)
RegisterItemEventHandler(eventHandler ItemEventHandler)
}
func NewConfigmapMgr(XDSUpdater model.XDSUpdater, namespace string, higressConfigController HigressConfigController, higressConfigLister listersv1.ConfigMapNamespaceLister) *ConfigmapMgr {
// ...
tracingController := NewTracingController(namespace)
configmapMgr.AddItemControllers(tracingController)
// ...
// 在这里初始化扩展配置,同时添加到 ItemControllers
configmapMgr.initEventHandlers()
return configmapMgr
}
Higress 开源贡献小组正在火热招募贡献者。早期参与开源更容易成为项目 Committer ,并有更多机会成为 Higress PMC(Project Management Committee) 的一员,参与主导 Higress 社区的前进方向。 欢迎加入 Higress 社区群:

原计划 9 月底搬新家,但是手头拮据,提前 2 个月搬的话可以省出 7000rmb
主要家里有三岁小孩,放置这么长时间也是处于此考虑。
主要异味来源是木工打的衣柜、书柜、餐边柜,柜体兔宝宝生态板,柜门千年舟,
是那种带着芬香气味的味道,现在虽然没有一开始浓重但是还是能闻出来。
由于我司一个神奇的活动,获得了一个 5k 块代付机会。规则是物品价格上限 10k ,但报销最多 5k ,不可买加油卡,购物卡,京东卡这种类似折现的东西。
突然发现平时也不怎么会省钱,所以想要的,能买得起的东西基本都买了,想来想去也想不出买点啥。
所以就想问问大家,有什么 5k 块左右可以提升幸福感的小玩意推荐。 这次买不上的,收录到我的败家 list 里面,嘿嘿~
今天无意中在 github 上发现了这个项目,点开发现 stars 挺多的,在 gitee 上 stars 更是惊人,有 73.4K 之多,想着 stars 这么多,项目应该不错,就 clone 到本地看下,准备看文档启动的时候问题来了,访问文档地址竟然要登录,这都没啥,你点击快速启动以及功能列表,会有个弹窗,要求你先 star 才能看。“后端手册”手册就更离谱了,要求你微信扫码加入星球,而加入星球需要支付 199 元人民币,也就是说,你要看到完整的文档,需要 star+支付 199 元人民币……
他项目的 README.md 写着“芋道,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用”,代码可以免费使用,文档要收费,没毛病[手动狗头]
不谈灵性,也不谈科学。
简单的问问你自己:此刻的你正在思考,你能意识到自己的存在。死是什么意思?为什么你会意识不到自己的存在?
之前一直用的一元机场,FSCLOUD 之类的,很便宜,就是跑路了,有 v 友推荐一下吗?就月付 1-3 元的,凑合用就行