前端技术
HTML
CSS
Javascript
前端框架和UI库
VUE
ReactJS
AngularJS
JQuery
NodeJS
JSON
Element-UI
Bootstrap
Material UI
服务端和客户端
Java
Python
PHP
Golang
Scala
Kotlin
Groovy
Ruby
Lua
.net
c#
c++
后端WEB和工程框架
SpringBoot
SpringCloud
Struts2
MyBatis
Hibernate
Tornado
Beego
Go-Spring
Go Gin
Go Iris
Dubbo
HessianRPC
Maven
Gradle
数据库
MySQL
Oracle
Mongo
中间件与web容器
Redis
MemCache
Etcd
Cassandra
Kafka
RabbitMQ
RocketMQ
ActiveMQ
Nacos
Consul
Tomcat
Nginx
Netty
大数据技术
Hive
Impala
ClickHouse
DorisDB
Greenplum
PostgreSQL
HBase
Kylin
Hadoop
Apache Pig
ZooKeeper
SeaTunnel
Sqoop
Datax
Flink
Spark
Mahout
数据搜索与日志
ElasticSearch
Apache Lucene
Apache Solr
Kibana
Logstash
数据可视化与OLAP
Apache Atlas
Superset
Saiku
Tesseract
系统与容器
Linux
Shell
Docker
Kubernetes
[API接口文档 ]的搜索结果
这里是文章列表。热门标签的颜色随机变换,标签颜色没有特殊含义。
点击某个标签可搜索标签相关的文章。
点击某个标签可搜索标签相关的文章。
转载文章
...码当中,关于RCU的文档比较齐全,你可以在 /DocumentaTIon/RCU/ 目录下找到这些文件。Paul E. McKenney 是内核中RCU源码的主要实现者,他也写了很多RCU方面的文章。今天我们就主要来说说linux内核rcu的机制详解。 在RCU的实现过程中,我们主要解决以下问题: 在读取过程中,另外一个线程删除了一个节点。删除线程可以把这个节点从链表中移除,但它不能直接销毁这个节点,必须等到所有的线程读取完成以后,才进行销毁操作。RCU中把这个过程称为宽限期(Grace period)。 在读取过程中,另外一个线程插入了一个新节点,而读线程读到了这个节点,那么需要保证读到的这个节点是完整的。这里涉及到了发布-订阅机制(Publish-Subscribe Mechanism)。 保证读取链表的完整性。新增或者删除一个节点,不至于导致遍历一个链表从中间断开。但是RCU并不保证一定能读到新增的节点或者不读到要被删除的节点。 宽限期 通过这个例子,方便理解这个内容。以下例子修改于Paul的文章。 struct foo {int a;char b;long c;};DEFINE_SPINLOCK(foo_mutex);struct foo gbl_foo;void foo_read (void){foo fp = gbl_foo;if ( fp != NULL )dosomething(fp-》a, fp-》b , fp-》c );}void foo_update( foo new_fp ){spin_lock(&foo_mutex);foo old_fp = gbl_foo;gbl_foo = new_fp;spin_unlock(&foo_mutex);kfee(old_fp);} 如上的程序,是针对于全局变量gbl_foo的操作。假设以下场景。有两个线程同时运行 foo_ read和foo_update的时候,当foo_ read执行完赋值操作后,线程发生切换;此时另一个线程开始执行foo_update并执行完成。当foo_ read运行的进程切换回来后,运行dosomething 的时候,fp已经被删除,这将对系统造成危害。为了防止此类事件的发生,RCU里增加了一个新的概念叫宽限期(Grace period)。 如下图所示: 图中每行代表一个线程,最下面的一行是删除线程,当它执行完删除操作后,线程进入了宽限期。宽限期的意义是,在一个删除动作发生后,它必须等待所有在宽限期开始前已经开始的读线程结束,才可以进行销毁操作。这样做的原因是这些线程有可能读到了要删除的元素。图中的宽限期必须等待1和2结束;而读线程5在宽限期开始前已经结束,不需要考虑;而3,4,6也不需要考虑,因为在宽限期结束后开始后的线程不可能读到已删除的元素。为此RCU机制提供了相应的API来实现这个功能。 void foo_read(void){rcu_read_lock();foo fp = gbl_foo;if ( fp != NULL )dosomething(fp-》a,fp-》b,fp-》c);rcu_read_unlock();}void foo_update( foo new_fp ){spin_lock(&foo_mutex);foo old_fp = gbl_foo;gbl_foo = new_fp;spin_unlock(&foo_mutex);synchronize_rcu();kfee(old_fp);} 其中foo_read中增加了rcu_read_lock和rcu_read_unlock,这两个函数用来标记一个RCU读过程的开始和结束。其实作用就是帮助检测宽限期是否结束。 foo_update增加了一个函数synchronize_rcu(),调用该函数意味着一个宽限期的开始,而直到宽限期结束,该函数才会返回。我们再对比着图看一看,线程1和2,在synchronize_rcu之前可能得到了旧的gbl_foo,也就是foo_update中的old_fp,如果不等它们运行结束,就调用kfee(old_fp),极有可能造成系统崩溃。而3,4,6在synchronize_rcu之后运行,此时它们已经不可能得到old_fp,此次的kfee将不对它们产生影响。 宽限期是RCU实现中最复杂的部分,原因是在提高读数据性能的同时,删除数据的性能也不能太差。 订阅——发布机制 当前使用的编译器大多会对代码做一定程度的优化,CPU也会对执行指令做一些优化调整,目的是提高代码的执行效率,但这样的优化,有时候会带来不期望的结果。如例: void foo_update( foo new_fp ){spin_lock(&foo_mutex);foo old_fp = gbl_foo;new_fp-》a = 1;new_fp-》b = ‘b’;new_fp-》c = 100;gbl_foo = new_fp;spin_unlock(&foo_mutex);synchronize_rcu();kfee(old_fp);} 这段代码中,我们期望的是6,7,8行的代码在第10行代码之前执行。但优化后的代码并不会对执行顺序做出保证。在这种情形下,一个读线程很可能读到 new_fp,但new_fp的成员赋值还没执行完成。单独线程执行dosomething(fp-》a, fp-》b , fp-》c ) 的 这个时候,就有不确定的参数传入到dosomething,极有可能造成不期望的结果,甚至程序崩溃。可以通过优化屏障来解决该问题,RCU机制对优化屏障做了包装,提供了专用的API来解决该问题。这时候,第十行不再是直接的指针赋值,而应该改为 : rcu_assign_pointer(gbl_foo,new_fp);rcu_assign_pointer的实现比较简单,如下:define rcu_assign_pointer(p, v) \__rcu_assign_pointer((p), (v), __rcu)define __rcu_assign_pointer(p, v, space) \do { \smp_wmb(); \(p) = (typeof(v) __force space )(v); \} while (0) 我们可以看到它的实现只是在赋值之前加了优化屏障 smp_wmb来确保代码的执行顺序。另外就是宏中用到的__rcu,只是作为编译过程的检测条件来使用的。 在DEC Alpha CPU机器上还有一种更强悍的优化,如下所示: void foo_read(void){rcu_read_lock();foo fp = gbl_foo;if ( fp != NULL )dosomething(fp-》a, fp-》b ,fp-》c);rcu_read_unlock();} 第六行的 fp-》a,fp-》b,fp-》c会在第3行还没执行的时候就预先判断运行,当他和foo_update同时运行的时候,可能导致传入dosomething的一部分属于旧的gbl_foo,而另外的属于新的。这样会导致运行结果的错误。为了避免该类问题,RCU还是提供了宏来解决该问题: define rcu_dereference(p) rcu_dereference_check(p, 0)define rcu_dereference_check(p, c) \__rcu_dereference_check((p), rcu_read_lock_held() || (c), __rcu)define __rcu_dereference_check(p, c, space) \({ \typeof(p) _________p1 = (typeof(p)__force )ACCESS_ONCE(p); \rcu_lockdep_assert(c, “suspicious rcu_dereference_check()” \usage”); \rcu_dereference_sparse(p, space); \smp_read_barrier_depends(); \(typeof(p) __force __kernel )(_________p1)); \})staTIc inline int rcu_read_lock_held(void){if (!debug_lockdep_rcu_enabled())return 1;if (rcu_is_cpu_idle())return 0;if (!rcu_lockdep_current_cpu_online())return 0;return lock_is_held(&rcu_lock_map);} 这段代码中加入了调试信息,去除调试信息,可以是以下的形式(其实这也是旧版本中的代码): define rcu_dereference(p) ({ \typeof(p) _________p1 = p; \smp_read_barrier_depends(); \(_________p1); \}) 在赋值后加入优化屏障smp_read_barrier_depends()。我们之前的第四行代码改为 foo fp = rcu_dereference(gbl_foo);,就可以防止上述问题。 数据读取的完整性 还是通过例子来说明这个问题: 如图我们在原list中加入一个节点new到A之前,所要做的第一步是将new的指针指向A节点,第二步才是将Head的指针指向new。这样做的目的是当插入操作完成第一步的时候,对于链表的读取并不产生影响,而执行完第二步的时候,读线程如果读到new节点,也可以继续遍历链表。如果把这个过程反过来,第一步head指向new,而这时一个线程读到new,由于new的指针指向的是Null,这样将导致读线程无法读取到A,B等后续节点。从以上过程中,可以看出RCU并不保证读线程读取到new节点。如果该节点对程序产生影响,那么就需要外部调用来做相应的调整。如在文件系统中,通过RCU定位后,如果查找不到相应节点,就会进行其它形式的查找,相关内容等分析到文件系统的时候再进行叙述。 我们再看一下删除一个节点的例子: 如图我们希望删除B,这时候要做的就是将A的指针指向C,保持B的指针,然后删除程序将进入宽限期检测。由于B的内容并没有变更,读到B的线程仍然可以继续读取B的后续节点。B不能立即销毁,它必须等待宽限期结束后,才能进行相应销毁操作。由于A的节点已经指向了C,当宽限期开始之后所有的后续读操作通过A找到的是C,而B已经隐藏了,后续的读线程都不会读到它。这样就确保宽限期过后,删除B并不对系统造成影响。 小结 RCU的原理并不复杂,应用也很简单。但代码的实现确并不是那么容易,难点都集中在了宽限期的检测上,后续分析源代码的时候,我们可以看到一些极富技巧的实现方式。 本篇文章为转载内容。原文链接:https://blog.csdn.net/m0_50662680/article/details/128449401。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-09-25 09:31:10
106
转载
转载文章
...基于RESTful API设计原则的WebService已成为现代应用开发的标准实践。最新的API网关技术如Kong、Envoy等,不仅提供了统一的安全认证、限流熔断等治理能力,还能简化WebService接口的管理和部署。例如,一篇近期的技术文章《使用Kong构建可扩展的微服务API网关》深入探讨了如何利用此类工具优化WebService性能,并确保其在大规模分布式环境中的高可用性。 另外,HTTP/3作为HTTP协议的最新版本,正在逐步被各大主流浏览器及服务器支持。相较于HTTP/1.1和HTTP/2,HTTP/3引入了QUIC协议,提供更快的连接建立速度、多路复用无阻塞传输,有效解决了延迟和丢包问题。阅读关于HTTP/3的最新研究与实践案例,比如《HTTP/3:下一代互联网传输协议的变革与应用》,将有助于我们掌握未来WebService通信的新趋势和技术细节。 此外,对于安全防护方面,随着网络攻击手段的日益复杂化,保障WebService的安全性至关重要。一篇题为《深度解析:如何强化你的WebService安全防护体系》的文章详述了多种常见的安全威胁及应对策略,包括但不限于DDoS防御、SQL注入防范、OAuth2.0授权机制的应用等,这对于提升自建WebService的安全等级具有极高的参考价值。 综上所述,在实际开发和运维过程中,结合最新的技术和最佳实践,不断优化和完善WebService的实现方案,既能提高系统的稳定性和效率,也能确保其在面对各种挑战时具备足够的安全性和适应性。
2023-05-30 18:31:58
91
转载
Javascript
...ortSignal接口的操作,比如fetch、XMLHttpRequest之类。如果你尝试在一个不支持AbortSignal的操作上使用它,那就会直接报错。另外啊,要是随便乱用 AbortError 可不好,比如说老是取消请求的话,系统可能就会被折腾得够呛,负担越来越重,你说是不是? 说到这里,我想起了之前开发的一个项目,当时为了优化性能,我给每个API请求都加了AbortController,结果发现有时候会导致页面加载速度反而变慢了。后来经过反复调试,我才意识到,频繁地取消请求其实是得不偿失的。所以啊,大家在使用AbortError的时候一定要权衡利弊,不能盲目追求“安全”。 --- 五、总结与展望 总的来说,AbortError是一个非常实用且有趣的错误类型。它不仅能让我们更轻松地搞定那些乱七八糟的异步任务,还能让代码变得更好懂、更靠谱!不过,就像任何工具一样,它也需要我们在实践中不断摸索和完善。 未来,随着前端开发越来越复杂,我相信AbortError会有更多的应用场景。不管是应对一大堆同时进行的任务,还是让咱们跟软件互动的时候更顺畅、更开心,它都绝对是我们离不开的得力助手!所以,各位小伙伴,不妨多尝试用它来解决实际问题,说不定哪天你会发现一个全新的解决方案呢! 好了,今天的分享就到这里啦。希望能给大家打开一点思路,也期待大家在评论区畅所欲言,分享你的想法!最后,祝大家coding愉快,早日成为编程界的高手!
2025-03-27 16:22:54
107
月影清风
ElasticSearch
...,比如说准不准用某个API,能不能访问特定的索引之类的。 json { "role": "custom_role", "cluster": ["monitor"], "indices": [ { "names": [ "logstash-" ], "privileges": [ "read", "view_index_metadata" ] } ] } 这段JSON定义了一个名为custom_role的角色,允许用户读取logstash-系列索引的数据。 --- 4. 日志审计与监控 最后,咱们得关注日志审计和监控。即使你做了所有的安全措施,也不能保证万无一失。定期检查日志和监控系统可以帮助我们及时发现问题。 4.1 日志审计 Elasticsearch自带的日志功能非常强大。你可以通过配置日志级别来记录不同级别的事件。例如,启用调试日志: yaml logger.org.elasticsearch: debug 将这条配置添加到logging.yml文件中即可。 4.2 监控工具 推荐使用Kibana来监控Elasticsearch的状态。装好Kibana之后,你就能通过网页界面瞅一眼你的集群健不健康、各个节点都在干嘛,还能看看性能指标啥的,挺直观的! 4.2.1 配置Kibana 在Kibana的配置文件kibana.yml中,添加以下内容: yaml elasticsearch.hosts: ["https://localhost:9200"] elasticsearch.username: "kibana_system" elasticsearch.password: "changeme" 然后重启Kibana服务,打开浏览器访问http://localhost:5601即可。 --- 5. 总结 好了,朋友们,今天的分享就到这里啦!优化Elasticsearch的安全性并不是一件容易的事,但只要我们用心去做,就能大大降低风险。从SSL/TLS加密到用户认证,再到日志审计和监控,每一个环节都很重要。 我希望这篇文章对你有所帮助,如果你还有其他问题或者经验分享,欢迎随时留言交流!让我们一起打造更安全、更可靠的Elasticsearch集群吧!
2025-05-12 15:42:52
99
星辰大海
转载文章
...imit.yaml apiVersion: v1kind: Podmetadata:name: memory-demospec:containers:- name: memory-demo-ctrimage: vish/stressresources:limits:memory: "200Mi"requests:memory: "100Mi"args:- -mem-total- 150Mi- -mem-alloc-size- 10Mi- -mem-alloc-sleep- 1s 在这个配置文件里,args代码段提供了容器所需的参数。-mem-total 150Mi告诉容器尝试申请150M 的内存。 创建Pod: kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/memory-request-limit.yaml --namespace=mem-example 验证Pod的容器是否正常运行: kubectl get pod memory-demo --namespace=mem-example 查看Pod的详细信息: kubectl get pod memory-demo --output=yaml --namespace=mem-example 这个输出显示了Pod里的容器申请了100M的内存和200M的内存限制。 ...resources:limits:memory: 200Mirequests:memory: 100Mi... 启动proxy以便我们可以访问Heapster服务: kubectl proxy 在另外一个命令行窗口,从Heapster服务获取内存使用情况: curl http://localhost:8001/api/v1/proxy/namespaces/kube-system/services/heapster/api/v1/model/namespaces/mem-example/pods/memory-demo/metrics/memory/usage 这个输出显示了Pod正在使用162,900,000字节的内存,大概就是150M。这很明显超过了申请 的100M,但是还没达到200M的限制。 {"timestamp": "2017-06-20T18:54:00Z","value": 162856960} 删除Pod: kubectl delete pod memory-demo --namespace=mem-example 超出容器的内存限制 只要节点有足够的内存资源,那容器就可以使用超过其申请的内存,但是不允许容器使用超过其限制的 资源。如果容器分配了超过限制的内存,这个容器将会被优先结束。如果容器持续使用超过限制的内存, 这个容器就会被终结。如果一个结束的容器允许重启,kubelet就会重启他,但是会出现其他类型的运行错误。 本实验,我们创建一个Pod尝试分配超过其限制的内存,下面的这个Pod的配置文档,它申请50M的内存, 内存限制设置为100M。 memory-request-limit-2.yaml apiVersion: v1kind: Podmetadata:name: memory-demo-2spec:containers:- name: memory-demo-2-ctrimage: vish/stressresources:requests:memory: 50Milimits:memory: "100Mi"args:- -mem-total- 250Mi- -mem-alloc-size- 10Mi- -mem-alloc-sleep- 1s 在配置文件里的args段里,可以看到容器尝试分配250M的内存,超过了限制的100M。 创建Pod: kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/memory-request-limit-2.yaml --namespace=mem-example 查看Pod的详细信息: kubectl get pod memory-demo-2 --namespace=mem-example 这时候,容器可能会运行,也可能会被杀掉。如果容器还没被杀掉,重复之前的命令直至 你看到这个容器被杀掉: NAME READY STATUS RESTARTS AGEmemory-demo-2 0/1 OOMKilled 1 24s 查看容器更详细的信息: kubectl get pod memory-demo-2 --output=yaml --namespace=mem-example 这个输出显示了容器被杀掉因为超出了内存限制。 lastState:terminated:containerID: docker://65183c1877aaec2e8427bc95609cc52677a454b56fcb24340dbd22917c23b10fexitCode: 137finishedAt: 2017-06-20T20:52:19Zreason: OOMKilledstartedAt: null 本实验里的容器可以自动重启,因此kubelet会再去启动它。输入多几次这个命令看看它是怎么 被杀掉又被启动的: kubectl get pod memory-demo-2 --namespace=mem-example 这个输出显示了容器被杀掉,被启动,又被杀掉,又被启动的过程: stevepe@sperry-1:~/steveperry-53.github.io$ kubectl get pod memory-demo-2 --namespace=mem-exampleNAME READY STATUS RESTARTS AGEmemory-demo-2 0/1 OOMKilled 1 37sstevepe@sperry-1:~/steveperry-53.github.io$ kubectl get pod memory-demo-2 --namespace=mem-exampleNAME READY STATUS RESTARTS AGEmemory-demo-2 1/1 Running 2 40s 查看Pod的历史详细信息: kubectl describe pod memory-demo-2 --namespace=mem-example 这个输出显示了Pod一直重复着被杀掉又被启动的过程: ... Normal Created Created container with id 66a3a20aa7980e61be4922780bf9d24d1a1d8b7395c09861225b0eba1b1f8511... Warning BackOff Back-off restarting failed container 查看集群里节点的详细信息: kubectl describe nodes 输出里面记录了容器被杀掉是因为一个超出内存的状况出现: Warning OOMKilling Memory cgroup out of memory: Kill process 4481 (stress) score 1994 or sacrifice child 删除Pod: kubectl delete pod memory-demo-2 --namespace=mem-example 配置超出节点能力范围的内存申请 内存的申请和限制是针对容器本身的,但是认为Pod也有容器的申请和限制是一个很有帮助的想法。 Pod申请的内存就是Pod里容器申请的内存总和,类似的,Pod的内存限制就是Pod里所有容器的 内存限制的总和。 Pod的调度策略是基于请求的,只有当节点满足Pod的内存申请时,才会将Pod调度到合适的节点上。 在这个实验里,我们创建一个申请超大内存的Pod,超过了集群里任何一个节点的可用内存资源。 这个容器申请了1000G的内存,这个应该会超过你集群里能提供的数量。 memory-request-limit-3.yaml apiVersion: v1kind: Podmetadata:name: memory-demo-3spec:containers:- name: memory-demo-3-ctrimage: vish/stressresources:limits:memory: "1000Gi"requests:memory: "1000Gi"args:- -mem-total- 150Mi- -mem-alloc-size- 10Mi- -mem-alloc-sleep- 1s 创建Pod: kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/memory-request-limit-3.yaml --namespace=mem-example 查看Pod的状态: kubectl get pod memory-demo-3 --namespace=mem-example 输出显示Pod的状态是Pending,因为Pod不会被调度到任何节点,所有它会一直保持在Pending状态下。 kubectl get pod memory-demo-3 --namespace=mem-exampleNAME READY STATUS RESTARTS AGEmemory-demo-3 0/1 Pending 0 25s 查看Pod的详细信息包括事件记录 kubectl describe pod memory-demo-3 --namespace=mem-example 这个输出显示容器不会被调度因为节点上没有足够的内存: Events:... Reason Message------ -------... FailedScheduling No nodes are available that match all of the following predicates:: Insufficient memory (3). 内存单位 内存资源是以字节为单位的,可以表示为纯整数或者固定的十进制数字,后缀可以是E, P, T, G, M, K, Ei, Pi, Ti, Gi, Mi, Ki.比如,下面几种写法表示相同的数值:alue: 128974848, 129e6, 129M , 123Mi 删除Pod: kubectl delete pod memory-demo-3 --namespace=mem-example 如果不配置内存限制 如果不给容器配置内存限制,那下面的任意一种情况可能会出现: 容器使用内存资源没有上限,容器可以使用当前节点上所有可用的内存资源。 容器所运行的命名空间有默认内存限制,容器会自动继承默认的限制。集群管理员可以使用这个文档 LimitRange来配置默认的内存限制。 内存申请和限制的原因 通过配置容器的内存申请和限制,你可以更加有效充分的使用集群里内存资源。配置较少的内存申请, 可以让Pod跟任意被调度。设置超过内存申请的限制,可以达到以下效果: Pod可以在负载高峰时更加充分利用内存。 可以将Pod的内存使用限制在比较合理的范围。 清理 删除命名空间,这会顺便删除命名空间里的Pod。 kubectl delete namespace mem-example 译者:NickSu86 原文链接 本篇文章为转载内容。原文链接:https://blog.csdn.net/Aria_Miazzy/article/details/99694937。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-12-23 12:14:07
497
转载
转载文章
...能,同时提供了丰富的API接口以供用户自定义插件和扩展功能。 此外,针对网络扫描攻击等行为,业界也提出了新的防御策略和技术。例如,基于人工智能的动态防火墙策略,可以根据网络流量特征自动调整规则,有效应对端口扫描等攻击行为,极大地提升了网络安全防护水平。 综上所述,在持续演进的网络安全领域,Libnids所涉及的数据包处理机制、TCP连接管理等功能是构建现代网络防御体系的基础,而结合最新的研究进展和技术应用,则有助于我们更好地理解和应对日趋复杂且变化多端的网络威胁环境。
2023-02-08 17:36:31
307
转载
Hadoop
...统(HDFS)和它的API库。为了更好地理解,我们可以一步步来分析。 3.1 HDFS的基本概念 HDFS是Hadoop的核心组件之一,它是用来存储大量数据的分布式文件系统。这就像是一个超大号的硬盘,不过它有点特别,不是集中在一个地方存东西,而是把数据切成小块,分散到不同的“小房间”里去。这样做的好处是即使某个节点坏了,也不会影响整个系统的运行。 HDFS还提供了一套丰富的接口,允许开发者自定义文件的操作行为。这就为实现跨访问控制协议迁移提供了可能性。 3.2 实现步骤 实现跨访问控制协议迁移大致分为以下几个步骤: (1)读取源系统的访问控制信息 第一步是获取源系统的访问控制信息。比如,如果你正在从Linux系统迁移到Windows系统,你需要先读取Linux上的ACL配置。 java // 示例代码:读取Linux ACL import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import java.io.IOException; public class AccessControlReader { public static void main(String[] args) throws IOException { Path path = new Path("/path/to/source/file"); FileSystem fs = FileSystem.get(new Configuration()); // 获取ACL信息 String acl = fs.getAclStatus(path).toString(); System.out.println("Source ACL: " + acl); } } 这段代码展示了如何使用Hadoop API读取Linux系统的ACL信息。可以看到,Hadoop已经为我们封装好了相关的API,调用起来非常方便。 (2)转换为目标系统的格式 接下来,我们需要将读取到的访问控制信息转换为目标系统的格式。比如,将Linux的ACL转换为Windows的NTFS权限。 java // 示例代码:模拟ACL到NTFS的转换 public class AclToNtfsConverter { public static void convert(String linuxAcl) { // 这里可以编写具体的转换逻辑 System.out.println("Converting ACL to NTFS: " + linuxAcl); } } 虽然这里只是一个简单的打印函数,但实际上你可以根据实际需求编写复杂的转换算法。 (3)应用到目标系统 最后一步是将转换后的权限应用到目标系统上。这一步同样可以通过Hadoop提供的API来完成。 java // 示例代码:应用NTFS权限 public class NtfsPermissionApplier { public static void applyPermissions(Path targetPath, String ntfsPermissions) { try { // 模拟应用权限的过程 System.out.println("Applying NTFS permissions to " + targetPath.toString() + ": " + ntfsPermissions); } catch (Exception e) { e.printStackTrace(); } } } 通过这三个步骤,我们就完成了从源系统到目标系统的访问控制协议迁移。 --- 四、实战演练 一个完整的案例 为了让大家更直观地理解,我准备了一个完整的案例。好啦,想象一下,我们现在要干的事儿就是把一个文件从一台Linux服务器搬去Windows服务器,而且还得保证这个文件在新家里的“门禁权限”跟原来一模一样,不能搞错! 4.1 准备工作 首先,确保你的开发环境中已经安装了Hadoop,并且配置好相关的依赖库。此外,还需要准备两台机器,一台装有Linux系统,另一台装有Windows系统。 4.2 编写代码 接下来,我们编写代码来实现迁移过程。首先是读取Linux系统的ACL信息。 java // 读取Linux ACL Path sourcePath = new Path("/source/file.txt"); FileSystem linuxFs = FileSystem.get(new Configuration()); String linuxAcl = linuxFs.getAclStatus(sourcePath).toString(); System.out.println("Linux ACL: " + linuxAcl); 然后,我们将这些ACL信息转换为NTFS格式。 java // 模拟ACL到NTFS的转换 AclToNtfsConverter.convert(linuxAcl); 最后,将转换后的权限应用到Windows系统上。 java // 应用NTFS权限 Path targetPath = new Path("\\\\windows-server\\file.txt"); NtfsPermissionApplier.applyPermissions(targetPath, "Full Control"); 4.3 执行结果 执行完上述代码后,你会发现文件已经被成功迁移到了Windows系统,并且保留了原有的访问控制设置。是不是很神奇? --- 五、总结与展望 通过这篇文章,我相信你对Hadoop支持文件的跨访问控制协议迁移有了更深的理解。Hadoop不仅是一个强大的工具,更是一种思维方式的转变。它就像个聪明的老师,不仅教我们怎么用分布式的思路去搞定问题,还时不时敲打我们:嘿,别忘了数据的安全和规矩可不能丢啊! 未来,随着技术的发展,Hadoop的功能会越来越强大。我希望你能继续探索更多有趣的话题,一起在这个充满挑战的世界里不断前行! 加油吧,程序员们!
2025-04-29 15:54:59
80
风轻云淡
转载文章
...llgc的时候会导致接口的响应速度特别慢,该如何排查和解决? 项目内存或者CPU占用率过高如何排查? ConcurrentHashmap原理 数据库分库分表 MQ相关,为什么kafka这么快,什么是零拷贝? 小算法题 http和https协议区别,具体原理 四面(Leader) 手画自己项目的架构图,并且针对架构和中间件提问 印象最深的一本技术书籍是什么? 五面(HR) 没什么过多的问题,主要就是聊了一下自己今后的职业规划,告知了薪资组成体系等等。 插播一条福利!!!最近整理了一套1000道面试题的文档(详细内容见文首推荐文章),以及大厂面试真题,和最近看的几本书。 需要刷题和跳槽的朋友,这些可以免费赠送给大家,帮忙转发文章,宣传一下,后台私信【面试】免费领取! 小天:好像问了两次看书的情况诶?现在面试还问这个? 程序员H:是啊,幸亏之前为了弄懂JVM还看了两本书,不然真不知道说啥了! 小天:看来,我也要找几本书去看了,感情没看过两本书都不敢跳槽了! 程序员H:对了,还有简历,告诉你一个捷径 简历尽量写好一些,项目经验突出: 1、自己的知识广度和深度 2、自身的优势 3、项目的复杂性和难度以及指标 4、自己对于项目做的贡献或者优化 程序员H:唉~这还不能走可怎么办呀!你说,我把主管打一顿,是不是马上就可以走了? 小天:... 查看全文 http://www.taodudu.cc/news/show-3387369.html 相关文章: 阿里菜鸟面经 Java后端开发 社招三年 已拿offer 阿里 菜鸟网络(一面) 2021年阿里菜鸟网络春招实习岗面试分享,简历+面试+面经全套资料! 阿里菜鸟国际Java研发面经(三面+总结):JVM+架构+MySQL+Redis等 2021年3月29日 阿里菜鸟实习面试(一面)(含部分总结) mongodb 子文档排序_猫鼬101:基础知识,子文档和人口简介 特征工程 计算方法Gauss-Jordan消去法求线性方程组的解 使用(VAE)生成建模,理解可变自动编码器背后的数学原理 视觉SLAM入门 -- 学习笔记 - Part2 带你入门nodejs第一天——node基础语法及使用 python3数据结构_Python3-数据结构 debezium-connect-oracle使用 相关数值分析多种算法代码 android iphone treeview,Android之IphoneTreeView带组指示器的ExpandableListView效果 nginx rewrite功能使用 3-3 OneHot编码 JavaWeb:shiro入门小案例 MySQL的定义、操作、控制、查询语言的用法 MongoDB入门学习(三):MongoDB的增删查改 赋值、浅复制和深复制解析 以及get/set应用 他是吴恩达导师,被马云聘为「达摩院」首座 Jordan 标准型定理 列主元的Gauss-Jordan消元法-python实现 Jordan 块的几何 若尔当型(The Jordan form) 第七章 其他神经网络类型 解决迁移系统后无法配置启用WindowsRE环境的问题 宝塔面板迁移系统盘/www到数据盘/home 使用vmware vconverter从物理机迁移系统到虚拟机P2V 本篇文章为转载内容。原文链接:https://blog.csdn.net/m0_62695120/article/details/124510157。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-03-08 20:01:49
69
转载
转载文章
...种Java平台的标准API,用于实现消息传递系统中的生产者-消费者模式。JMS使得Java应用程序可以发送、接收和读取消息,从而实现了分布式应用之间的解耦和异步通信。在本文的语境中,Java通过JMS与Oracle AQ集成,监听并处理队列中的消息。 PL/SQL , PL/SQL是Oracle数据库特有的过程化SQL语言,它扩展了SQL的功能,允许开发人员编写包含条件判断、循环和其他复杂逻辑的存储过程、函数、触发器等数据库对象。在文章中,使用PL/SQL执行了一系列对Oracle AQ的操作,如创建队列、启动队列、入队和出队消息等。 JDBC连接参数类 , Java Database Connectivity (JDBC) 连接参数类是Java程序中用于存储数据库连接信息的类。在文中提到的JmsConfig类中,包含了诸如用户名、密码、数据库URL以及目标队列名称等连接参数,这些参数被用于初始化和管理到Oracle数据库的JDBC连接,以便Java应用程序能够与Oracle AQ进行交互。 CustomDatumFactory与CustomDatum , 在Java与Oracle数据库类型转换过程中,CustomDatumFactory和CustomDatum是Oracle JDBC驱动提供的接口和类,用于将Oracle数据库的自定义数据类型(如在本例中的demo_queue_payload_type)转换为Java对象,以便在Java应用程序中处理。CustomDatumFactory负责创建和解析CustomDatum对象,而CustomDatum则表示一个可定制的数据结构,可以与数据库中的自定义数据类型相对应。
2023-12-17 14:22:22
140
转载
转载文章
...ES6 新增的一个 API,它是一个对象,字面的意思是反射 Reflect 的作用: 它主要提供了很多操作 JavaScript 对象的方法,有点像 Object 中操作对象的方法 比如 Reflect.getPrototypeOf(target) 类似于 Object.getPrototypeOf() 比如 Reflect.defineProperty(target, propertyKey, attributes) 类似于 Object.defineProperty() 如果我们有 Object 可以做这些操作,那么为什么还需要有Reflect这样的新增对象呢? 这是因为在早期的 ECMA 规范中没有考虑到这种对 对象本身 的操作如何设计会更加规范,所以将这些 API 放到了 Object上面 但是 Object 作为一个构造函数,这些操作实际上放到它身上并不合适 另外还包含一些类似于 in、delete 操作符,让 JS 看起来是会有一些奇怪的 所以在 ES6 中新增了 Reflect,让我们这些操作都集中到了 Reflect 对象上 那么 Object 和 Reflect 对象之间的 API 关系,可以参考 MDN 文档: 比较 Reflect 和 Object 方法 3.2 Reflect 的常见方法 Reflect中有哪些常见的方法呢?它和Proxy是一一对应的,也是13个 Reflect.getPrototypeOf(target) 类似于 Object.getPrototypeOf() Reflect.setPrototypeOf(target, prototype) 设置对象原型的函数. 返回一个 Boolean, 如果更新成功,则返回 true Reflect.isExtensible(target) 类似于 Object.isExtensible() Reflect.preventExtensions(target) 类似于 Object.preventExtensions() , 返回一个 Boolean Reflect.getOwnPropertyDescriptor(target, propertyKey) 类似于 Object.getOwnPropertyDescriptor() , 如果对象中存在该属性,则返回对应的属性描述符, 否则返回 undefined Reflect.defineProperty(target, propertyKey, attributes) 和 Object.defineProperty() 类似, 如果设置成功就会返回 true Reflect.ownKeys(target) 返回一个包含所有自身属性(不包含继承属性)的数组 (类似于 Object.keys(), 但不会受 enumerable 影响) Reflect.has(target, propertyKey) 判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同 Reflect.get(target, propertyKey[, receiver]) 获取对象身上某个属性的值,类似于 target[name] Reflect.set(target, propertyKey, value[, receiver]) 将值分配给属性的函数,返回一个 Boolean,如果更新成功,则返回 true Reflect.deleteProperty(target, propertyKey) 作为函数的 delete 操作符,相当于执行 delete target[name] Reflect.apply(target, thisArgument, argumentsList) 对一个函数进行调用操作,同时可以传入一个数组作为调用参数。和 Function.prototype.apply() 功能类似 Reflect.construct(target, argumentsList[, newTarget]) 对构造函数进行 new 操作,相当于执行 new target(...args) 3.3 Reflect 的使用 那么我们可以将之前Proxy案例中对原对象的操作,都修改为Reflect来操作 const obj = {name: 'why',age: 18}const objProxy = new Proxy(obj, {get: function (target, key) {console.log(监听到obj对象的${key}属性被访问了)return Reflect.get(target, key)// return target[key] // 对原来对象进行了直接操作},set: function (target, key, newValue) {console.log(监听到obj对象的${key}属性被设置值)Reflect.set(target, key, newValue)// target[key] = newValue // 对原来对象进行了直接操作} })objProxy.name = 'kobe'console.log(objProxy.name)/ 监听到obj对象的name属性被设置值监听到obj对象的name属性被访问了kobe/ 3.4 Receiver的作用 我们发现在使用getter、setter的时候有一个receiver的参数,它的作用是什么呢? 如果我们的源对象(obj)有 setter 、getter 的访问器属性,那么可以通过 receiver 来改变里面的 this const obj = {_name: 'why',get name() {return this._name // 不使用receiver, _name属性的操作不会被objProxy代理,因为this指向obj},set name(newValue) {this._name = newValue} }const objProxy = new Proxy(obj, {get: function (target, key, receiver) {// receiver 是创建出来的代理对象console.log('get 方法被访问-------', key, receiver)console.log(objProxy === receiver) // truereturn Reflect.get(target, key, receiver)},set: function (target, key, newValue, receiver) {Reflect.set(target, key, newValue, receiver)} })objProxy.name = 'kobe'console.log(objProxy.name) // kobe/ get 方法被访问------- name { _name: 'kobe', name: [Getter/Setter] }trueget 方法被访问------- _name { _name: 'kobe', name: [Getter/Setter] }truekobe/ 3.5 Reflect 的 construct function Student(name, age) {this.name = namethis.age = age}function Teacher() {}const stu = new Student('why', 18)console.log(stu)console.log(stu.__proto__ === Student.prototype)/ Student { name: 'why', age: 18 }true/// 执行 Student 函数中的内容,但是创建出来的对象是 Teacher 对象const teacher = Reflect.construct(Student, ['why', 18], Teacher)console.log(teacher)console.log(teacher.__proto__ === Teacher.prototype)/ Teacher { name: 'why', age: 18 }true/ 4. 响应式 4.1 什么是响应式? 先来看一下响应式意味着什么?我们来看一段代码: m 有一个初始化的值,有一段代码使用了这个值; 那么在 m 有一个新的值时,这段代码可以自动重新执行 let m = 0// 一段代码console.log(m)console.log(m 2)console.log(m 2)m = 200 上面的这样一种可以自动响应数据变量的代码机制,我们就称之为是响应式的 对象的响应式 4.2 响应式函数设计 首先,执行的代码中可能不止一行代码,所以我们可以将这些代码放到一个函数中: 那么问题就变成了,当数据发生变化时,自动去执行某一个函数; 但是有一个问题:在开发中是有很多的函数的,如何区分一个函数需要响应式,还是不需要响应式呢? 很明显,下面的函数中 foo 需要在 obj 的 name 发生变化时,重新执行,做出相应; bar 函数是一个完全独立于 obj 的函数,它不需要执行任何响应式的操作; // 对象的响应式const obj = {name: 'why',age: 18}function foo() {const newName = obj.nameconsole.log('你好啊,李银河')console.log('Hello World')console.log(obj.name)}function bar() {console.log('普通的其他函数')console.log('这个函数不需要有任何的响应式')}obj.name = 'kobe' // name 发生改变时候 foo 函数执行 响应式函数的实现 watchFn 如何区分响应式函数? 这个时候我们封装一个新的函数 watchFn 凡是传入到 watchFn 的函数,就是需要响应式的 其他默认定义的函数都是不需要响应式的 / 封装一个响应式的函数 /let reactiveFns = []function watchFn(fn) {reactiveFns.push(fn)}// 对象的响应式const obj = {name: 'why',age: 18}watchFn(function foo() {const newName = obj.nameconsole.log('你好啊,李银河')console.log('Hello World')console.log(obj.name)})watchFn(function demo() {console.log(obj.name, 'demo function ---------')})function bar() {console.log('普通的其他函数')console.log('这个函数不需要有任何的响应式')}obj.name = 'kobe' // name 发生改变时候 foo 函数执行reactiveFns.forEach((fn) => {fn()}) 4.3 响应式依赖的收集 目前收集的依赖是放到一个数组中来保存的,但是这里会存在数据管理的问题: 在实际开发中需要监听很多对象的响应式 这些对象需要监听的不只是一个属性,它们很多属性的变化,都会有对应的响应式函数 不可能在全局维护一大堆的数组来保存这些响应函数 所以要设计一个类,这个类用于管理某一个对象的某一个属性的所有响应式函数: 相当于替代了原来的简单 reactiveFns 的数组; class Depend {constructor() {this.reactiveFns = []}addDepend(reactiveFn) {this.reactiveFns.push(reactiveFn)}notify() {this.reactiveFns.forEach((fn) => {fn()})} }const depend = new Depend()function watchFn(fn) {depend.addDepend(fn)}// 对象的响应式const obj = {name: 'why', // depend 对象age: 18 // depend 对象}watchFn(function foo() {const newName = obj.nameconsole.log('你好啊,李银河')console.log('Hello World')console.log(obj.name)})watchFn(function demo() {console.log(obj.name, 'demo function ---------')})function bar() {console.log('普通的其他函数')console.log('这个函数不需要有任何的响应式')}obj.name = 'kobe'depend.notify() 4.4 监听对象的变化 那么接下来就可以通过之前的方式来监听对象的变化: 方式一:通过 Object.defineProperty 的方式(vue2采用的方式); 方式二:通过 new Proxy 的方式(vue3采用的方式); 我们这里先以Proxy的方式来监听 class Depend {constructor() {this.reactiveFns = []}addDepend(reactiveFn) {this.reactiveFns.push(reactiveFn)}notify() {this.reactiveFns.forEach((fn) => {fn()})} }const depend = new Depend()function watchFn(fn) {depend.addDepend(fn)}// 对象的响应式const obj = {name: 'why', // depend 对象age: 18 // depend 对象}// 监听对象的属性变化:Proxy(vue3)/Object.defineProperty(vue2)const objProxy = new Proxy(obj, {get: function (target, key, receiver) {return Reflect.get(target, key, receiver)},set: function (target, key, newValue, receiver) {Reflect.set(target, key, newValue, receiver)depend.notify()} })watchFn(function foo() {const newName = objProxy.nameconsole.log('你好啊,李银河')console.log('Hello World')console.log(objProxy.name)})watchFn(function demo() {console.log(objProxy.name, 'demo function ---------')})objProxy.name = 'kobe'objProxy.name = 'james'/ 你好啊,李银河Hello Worldkobekobe demo function ---------你好啊,李银河Hello Worldjamesjames demo function ---------/ 4.5 对象的依赖管理 目前是创建了一个 Depend 对象,用来管理对于 name 变化需要监听的响应函数: 但是实际开发中我们会有不同的对象,另外会有不同的属性需要管理; 如何可以使用一种数据结构来管理不同对象的不同依赖关系呢? 在前面我们刚刚学习过 WeakMap,并且在学习 WeakMap 的时候我讲到了后面通过 WeakMap 如何管理这种响应式的数据依赖: 实现 可以写一个 getDepend 函数专门来管理这种依赖关系 / 封装一个获取depend的函数 /const taregtMap = new WeakMap()function getDepend(target, key) {// 根据target对象获取mapconst map = taregtMap.get(target)if (!map) {map = new Map()taregtMap.set(target, map)}// 根据key获取depend对象const depend = map.get(key)if (!depend) {depend = new Depend()map.set(key, depend)}return depend}// 监听对象的属性变化:Proxy(vue3)/Object.defineProperty(vue2)const objProxy = new Proxy(obj, {get: function (target, key, receiver) {return Reflect.get(target, key, receiver)},set: function (target, key, newValue, receiver) {Reflect.set(target, key, newValue, receiver)const depend = getDepend(target, key)depend.notify()} }) 正确的依赖收集 我们之前收集依赖的地方是在 watchFn 中: 但是这种收集依赖的方式我们根本不知道是哪一个 key 的哪一个 depend 需要收集依赖; 只能针对一个单独的 depend 对象来添加你的依赖对象; 那么正确的应该是在哪里收集呢?应该在我们调用了 Proxy 的 get 捕获器时 因为如果一个函数中使用了某个对象的 key,那么它应该被收集依赖 / 封装一个响应式函数 /let activeReactviceFn = nullfunction watchFn(fn) {activeReactviceFn = fnfn()activeReactviceFn = null}/ 封装一个获取depend的函数 /const taregtMap = new WeakMap()function getDepend(target, key) {// 根据target对象获取maplet map = taregtMap.get(target)if (!map) {map = new Map()taregtMap.set(target, map)}// 根据key获取depend对象let depend = map.get(key)if (!depend) {depend = new Depend()map.set(key, depend)}return depend}// 监听对象的属性变化:Proxy(vue3)/Object.defineProperty(vue2)const objProxy = new Proxy(obj, {get: function (target, key, receiver) {// 根据 target key 获取对应的 depnedconst depend = getDepend(target, key)// 给 depend 对象中添加响应式函数activeReactviceFn && depend.addDepend(activeReactviceFn)return Reflect.get(target, key, receiver)},set: function (target, key, newValue, receiver) {Reflect.set(target, key, newValue, receiver)const depend = getDepend(target, key)depend.notify()} }) 4.6 对 Depend 重构 两个问题: 问题一:如果函数中有用到两次 key,比如 name,那么这个函数会被收集两次 问题二:我们并不希望将添加 reactiveFn 放到 get 中,因为它是属于 Depend 的行为 所以我们需要对 Depend 类进行重构: 解决问题一的方法:不使用数组,而是使用 Set 解决问题二的方法:添加一个新的方法,用于收集依赖 // 保存当前需要收集的响应式函数let activeReactviceFn = nullclass Depend {constructor() {this.reactiveFns = new Set()}depend() {if (activeReactviceFn) {this.reactiveFns.add(activeReactviceFn)} }addDepend(reactiveFn) {this.reactiveFns.add(reactiveFn)}notify() {this.reactiveFns.forEach((fn) => {fn()})} }// 对象的响应式const obj = {name: 'why', // depend 对象age: 18 // depend 对象}/ 封装一个响应式函数 /function watchFn(fn) {activeReactviceFn = fnfn()activeReactviceFn = null}/ 封装一个获取depend的函数 /const taregtMap = new WeakMap()function getDepend(target, key) {// 根据target对象获取maplet map = taregtMap.get(target)if (!map) {map = new Map()taregtMap.set(target, map)}// 根据key获取depend对象let depend = map.get(key)if (!depend) {depend = new Depend()map.set(key, depend)}return depend}// 监听对象的属性变化:Proxy(vue3)/Object.defineProperty(vue2)const objProxy = new Proxy(obj, {get: function (target, key, receiver) {// 根据 target key 获取对应的 depnedconst depend = getDepend(target, key)// 给 depend 对象中添加响应式函数depend.depend()return Reflect.get(target, key, receiver)},set: function (target, key, newValue, receiver) {Reflect.set(target, key, newValue, receiver)const depend = getDepend(target, key)depend.notify()} })watchFn(function () {console.log(objProxy.name, '--------------')console.log(objProxy.name, '++++++++++++++')})objProxy.name = 'kobe'/ why --------------why ++++++++++++++kobe --------------kobe ++++++++++++++/ 4.7 创建响应式对象 目前的响应式是针对于obj一个对象的,我们可以创建出来一个函数,针对所有的对象都可以变成响应式对象 / 保存当前需要收集的响应式函数 /let activeReactviceFn = null/ 依赖收集类 /class Depend {constructor() {this.reactiveFns = new Set()}depend() {if (activeReactviceFn) {this.reactiveFns.add(activeReactviceFn)} }addDepend(reactiveFn) {this.reactiveFns.add(reactiveFn)}notify() {this.reactiveFns.forEach((fn) => {fn()})} }/ 封装一个响应式函数 /function watchFn(fn) {activeReactviceFn = fnfn()activeReactviceFn = null}/ 封装一个获取depend的函数 /const taregtMap = new WeakMap()function getDepend(target, key) {// 根据target对象获取maplet map = taregtMap.get(target)if (!map) {map = new Map()taregtMap.set(target, map)}// 根据key获取depend对象let depend = map.get(key)if (!depend) {depend = new Depend()map.set(key, depend)}return depend}/ 创建响应式对象函数 /function reactive(obj) {// 监听对象的属性变化:Proxy(vue3)/Object.defineProperty(vue2)return new Proxy(obj, {get: function (target, key, receiver) {// 根据 target key 获取对应的 depnedconst depend = getDepend(target, key)// 给 depend 对象中添加响应式函数depend.depend()return Reflect.get(target, key, receiver)},set: function (target, key, newValue, receiver) {Reflect.set(target, key, newValue, receiver)const depend = getDepend(target, key)depend.notify()} })}const info = reactive({address: '广州市',height: 1.88})watchFn(() => {console.log(info.address, '---')})info.address = '北京市' 4.8 Vue2 响应式原理 前面所实现的响应式的代码,其实就是 Vue3 中的响应式原理: Vue3 主要是通过 Proxy 来监听数据的变化以及收集相关的依赖的 Vue2 中通过 Object.defineProerty的方式来实现对象属性的监听 可以将 reactive 函数进行如下的重构: 在传入对象时,我们可以遍历所有的 key,并且通过属性存储描述符来监听属性的获取和修改 在 setter 和 getter 方法中的逻辑和前面的 Proxy 是一致的 / 保存当前需要收集的响应式函数 /let activeReactviceFn = null/ 依赖收集类 /class Depend {constructor() {this.reactiveFns = new Set()}depend() {if (activeReactviceFn) {this.reactiveFns.add(activeReactviceFn)} }addDepend(reactiveFn) {this.reactiveFns.add(reactiveFn)}notify() {this.reactiveFns.forEach((fn) => {fn()})} }/ 封装一个响应式函数 /function watchFn(fn) {activeReactviceFn = fnfn()activeReactviceFn = null}/ 封装一个获取depend的函数 /const taregtMap = new WeakMap()function getDepend(target, key) {// 根据target对象获取maplet map = taregtMap.get(target)if (!map) {map = new Map()taregtMap.set(target, map)}// 根据key获取depend对象let depend = map.get(key)if (!depend) {depend = new Depend()map.set(key, depend)}return depend}/ 创建响应式对象函数 /function reactive(obj) {Object.keys(obj).forEach((key) => {let value = obj[key]Object.defineProperty(obj, key, {get: function () {const dep = getDepend(obj, key)dep.depend()return value},set: function (newValue) {value = newValueconst dep = getDepend(obj, key)dep.notify()} })})return obj}const info = reactive({address: '广州市',height: 1.88})watchFn(() => {console.log(info.address, '---')})info.address = '北京市' 本篇文章为转载内容。原文链接:https://blog.csdn.net/wanghuan1020/article/details/126774033。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-01-11 12:37:47
680
转载
转载文章
...览器支持的File API和Blob对象,将大文件分割成多个小块进行独立上传的技术。在本文中,该技术被Plupload库采用以解决大容量文件上传时可能遇到的性能、稳定性和断点续传等问题。通过分片上传,即使在网络不稳定或中断的情况下,也可以仅重新上传未成功上传的分片,从而提高上传效率并确保数据完整性。 Plupload前端脚本库 , Plupload是一个强大的JavaScript库,主要用于实现跨浏览器的文件上传功能。它能够自动检测并适应不同的运行环境(如HTML5、Flash、Silverlight或传统的HTML4),选择最合适的上传方式。在文章中,开发者借助Plupload库封装了HTML5分片上传技术,并提供了丰富的事件监听接口,使得开发者可以方便地处理文件上传过程中的各种状态,包括文件选取、上传进度、成功或失败回调等。 multipart_params参数 , multipart_params是在使用Plupload库时的一个自定义HTTP请求参数设置项。在实际上传过程中,用户可以通过这个参数向服务器端传递额外的信息,例如在文中提到的type=misoft,用于标识上传文件的类型或用途。在后端代码UploadCoursePackage.ashx中,可以从请求参数中获取到这些自定义参数值,并根据它们执行相应的业务逻辑。这一特性增强了上传功能的灵活性和可定制性。
2023-12-19 09:43:46
128
转载
转载文章
...ents/操作系统/文档/19/OS-kernel-win-sheet/'ckernel_u.asm : ckernel.o....crack_u.asm : crack.o./objconv -fnasm crack.o crack_u.asmcrack.o : crack.cgcc -m32 -fno-stack-protector -fno-asynchronous-unwind-tables -s -c -o crack.o crack.c 然后我们在本地目录下,把api_call.asm拷贝一份,并命名为crack_call.asm,后者内容与前者完全相同,只不过稍微有那么一点点改变,例如: BITS 32mov AX, 30 8mov DS, axcall mainmov edx, 4 ;返回内核int 02Dh.... 这里需要注意,语句: mov AX, 30 8mov DS, ax 其中30对应的就是前面显示的0x1E,这两句汇编的作用是,把程序crack的数据段设置成下标为30的全局描述符所指向的内存段一致。这就意味着crack进程所使用的数据段就跟hlt启动的进程所使用的数据段一致了!于是在crack.c中,它对内存地址为0x123的地方写入字符串”crack”,那就意味着对hlt加载用户进程的内存空间写入对应字符串! 完成上面代码后,我们在java项目中,增加代码,一是用来编译crack进程,而是把crack代码写入虚拟磁盘。在OperatingSystem.java中,将代码做如下添加: public void makeFllopy() {writeFileToFloppy("kernel.bat", false, 1, 1);....header = new FileHeader();header.setFileName("crack");header.setFileExt("exe");file = new File("crack.bat");in = null;try {in = new FileInputStream(file);long len = file.length();int count = 0;while (count < file.length()) {bbuf[count] = (byte) in.read();count++;}in.close();}catch(IOException e) {e.printStackTrace();return;}header.setFileContent(bbuf);fileSys.addHeader(header);....}public static void main(String[] args) {CKernelAsmPrecessor kernelPrecessor = new CKernelAsmPrecessor();kernelPrecessor.process();kernelPrecessor.createKernelBinary();CKernelAsmPrecessor appPrecessor = new CKernelAsmPrecessor("hlt.bat", "app_u.asm", "app.asm", "api_call.asm");appPrecessor.process();appPrecessor.createKernelBinary();CKernelAsmPrecessor crackPrecessor = new CKernelAsmPrecessor("crack.bat", "crack_u.asm", "crack.asm", "crack_call.asm");crackPrecessor.process();crackPrecessor.createKernelBinary();OperatingSystem op = new OperatingSystem("boot.bat");op.makeFllopy();} 在main函数中,我们把crack.c及其附属汇编文件结合在一起,编译成二进制文件crack.bat,在makeFllopy中,我们把编译后的crack.bat二进制数据读入,并把它写入到虚拟磁盘中,当系统运行起来后,可以把crack.bat二进制内容作为进程加载执行。 完成上面代码后,回到内核的C语言部分,也就是write_vga_desktop.c做一些修改,在kernel_api函数中,修改如下: int kernel_api(int edi, int esi, int ebp, int esp,int ebx, int edx, int ecx, int eax) {....else if (edx == 14) {sheet_free(shtctl, (struct SHEET)ebx);//change herecons_putstr((char)(task->pTaskBuffer->pDataSeg + 0x123));}....}void console_task(struct SHEET sheet, int memtotal) {....for(;;) {....else if (i == KEY_RETURN) {....else if (strcmp(cmdline, "crack") == 1) {cmd_execute_program("crack.exe");}....}....} 在kernel_api中,if(edx == 14)对应的api调用是api_closewin,也就是当用户进程关闭窗口时,我们把进程数据偏移0x123处的数据当做字符串打印到控制台窗口上,在console_task控制台进程主函数中,我们增加了对命令crack的响应,当用户在控制台上输入命令”crack”时,将crack代码加载到内核中运行。上面代码完成后,编译内核,然后用虚拟机将内核加载,系统启动后,我们现在一个控制台中输入hlt,先启动用户进程。然后点击”shift + w”,启动另一个控制台窗口,在其中输入crack,运行crack程序: 接着把点击tab键,把焦点恢复到窗口task_a,然后用鼠标点击运行hlt命令的窗口,把输入焦点切换到该控制台,然后再次点击tab键,把执行权限提交给运行hlt命令的控制台,此时点击回车,介绍用户进程启动的窗口,结果情况如下: 此时我们可以看到,运行hlt命令,执行用户进程的控制台窗口居然输出了字符串”crack”,而这个字符串正是crack.c在执行时,写入地址0x123的字符串。这就意味着一个恶意进程成功修改了另一个进程的内存数据,也相当于一个流氓程序把一只咸猪手伸到其他用户进程的裙底,蹂躏一番后留下了猥琐的证据。 那么如何防范恶意进程对其他程序的非法入侵呢,这就得使用CPU提供的LDT机制,也就是局部描述符表,该机制的使用,我们将在下一节详细讲解。更详细的讲解和代码演示调试,请参看视频: 更详细的讲解和代码调试演示过程,请参看视频 Linux kernel Hacker, 从零构建自己的内核 更多技术信息,包括操作系统,编译器,面试算法,机器学习,人工智能,请关照我的公众号: 本篇文章为转载内容。原文链接:https://blog.csdn.net/tyler_download/article/details/78731905。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-03-14 19:08:07
256
转载
Kafka
...特性,包括增强型事务API、更高效的压缩算法以及对多租户环境的支持。这些更新旨在帮助企业更好地满足复杂业务场景的需求,同时也反映了Kafka社区对于技术创新的不懈追求。 此外,关于Kafka与ZooKeeper的关系,业界普遍关注其未来的演进方向。尽管Confluent正在推动KRaft(Kafka Raft-based Controller)项目,试图完全摆脱ZooKeeper的依赖,但在短期内,ZooKeeper仍将在许多传统部署环境中占据主导地位。因此,对于正在使用Kafka的企业而言,如何平衡现有基础设施与新技术之间的过渡,成为了一个值得深思的问题。 从长远来看,Kafka的成功离不开开源社区的支持。正如Apache软件基金会所倡导的理念,“开放、协作、共享”始终是推动技术创新的核心动力。在未来,随着更多企业和开发者加入到Kafka生态中,我们有理由相信,这一技术将继续保持旺盛的生命力,并在更多领域发挥重要作用。
2025-04-05 15:38:52
96
彩虹之上
转载文章
...化技术提供一个统一的API接口,其中包括KVM、Xen以及其他一些虚拟化平台。在本文中,libvirt用于管理和监控KVM虚拟机,包括创建、启动、停止、迁移等操作,以及配置网络和存储资源。通过libvirt,管理员可以在不同虚拟化技术之间保持一致的操作体验,同时简化虚拟环境的管理工作流程。
2023-04-06 08:58:59
122
转载
转载文章
...者提供了更简洁直观的API和强大的功能集。 3. 跨平台UI工具包Qt Jambi:尽管Java Swing是纯Java环境下的GUI解决方案,但也有其他跨平台工具包值得关注,例如Qt Jambi,它允许开发者使用Java编写原生速度和外观的应用程序,并兼容多种操作系统。 4. 无障碍性设计原则在Swing中的应用:针对日益增长的无障碍需求,开发者应了解并遵循WCAG标准,在Swing应用程序中实施无障碍设计,如提供键盘导航支持、可调整的文字大小及高对比度模式等。 5. Swing组件最佳实践分享:查阅最新的开发者博客和论坛讨论,可以发现众多关于如何优化Swing组件性能、处理并发问题以及改善用户体验的实际案例和建议,这些都能帮助你更好地运用Swing进行复杂GUI的设计与实现。 综上所述,不断跟进最新的GUI开发趋势和技术发展,结合实际项目需求,灵活运用和扩展Swing或其他相关框架,将有助于打造更为出色和易用的桌面应用程序。
2023-01-18 08:36:23
526
转载
转载文章
...发,它们常用在套接字接口的文件描述符中。 水平触发:只要文件描述符可以非阻塞地执行 I/O ,就会触发通知。也就是说,应用程序可以随时检查文件描述符的状态,然后再根据状态,进行 I/O 操作。 边缘触发:只有在文件描述符的状态发生改变(也就是 I/O 请求达到)时,才发送一次通知。这时候,应用程序需要尽可能多地执行 I/O,直到无法继续读写,才可以停止。如果 I/O 没执行完,或者因为某种原因没来得及处理,那么这次通知也就丢失了。 I/O 多路复用的方法有很多实现方法,我带你来逐个分析一下。 第一种,使用非阻塞 I/O 和水平触发通知,比如使用 select 或者 poll。 根据刚才水平触发的原理,select 和 poll 需要从文件描述符列表中,找出哪些可以执行 I/O ,然后进行真正的网络 I/O 读写。由于 I/O 是非阻塞的,一个线程中就可以同时监控一批套接字的文件描述符,这样就达到了单线程处理多请求的目的。所以,这种方式的最大优点,是对应用程序比较友好,它的 API 非常简单。 但是,应用软件使用 select 和 poll 时,需要对这些文件描述符列表进行轮询,这样,请求数多的时候就会比较耗时。并且,select 和 poll 还有一些其他的限制。 select 使用固定长度的位相量,表示文件描述符的集合,因此会有最大描述符数量的限制。比如,在 32 位系统中,默认限制是 1024。并且,在 select 内部,检查套接字状态是用轮询的方法,再加上应用软件使用时的轮询,就变成了一个 O(n^2) 的关系。 而 poll 改进了 select 的表示方法,换成了一个没有固定长度的数组,这样就没有了最大描述符数量的限制(当然还会受到系统文件描述符限制)。但应用程序在使用 poll 时,同样需要对文件描述符列表进行轮询,这样,处理耗时跟描述符数量就是 O(N) 的关系。 除此之外,应用程序每次调用 select 和 poll 时,还需要把文件描述符的集合,从用户空间传入内核空间,由内核修改后,再传出到用户空间中。这一来一回的内核空间与用户空间切换,也增加了处理成本。 有没有什么更好的方式来处理呢?答案自然是肯定的。 第二种,使用非阻塞 I/O 和边缘触发通知,比如 epoll。既然 select 和 poll 有那么多的问题,就需要继续对其进行优化,而 epoll 就很好地解决了这些问题。 epoll 使用红黑树,在内核中管理文件描述符的集合,这样,就不需要应用程序在每次操作时都传入、传出这个集合。 epoll 使用事件驱动的机制,只关注有 I/O 事件发生的文件描述符,不需要轮询扫描整个集合。 不过要注意,epoll 是在 Linux 2.6 中才新增的功能(2.4 虽然也有,但功能不完善)。由于边缘触发只在文件描述符可读或可写事件发生时才通知,那么应用程序就需要尽可能多地执行 I/O,并要处理更多的异常事件。 第三种,使用异步 I/O(Asynchronous I/O,简称为 AIO)。 在前面文件系统原理的内容中,我曾介绍过异步 I/O 与同步 I/O 的区别。异步 I/O 允许应用程序同时发起很多 I/O 操作,而不用等待这些操作完成。而在 I/O 完成后,系统会用事件通知(比如信号或者回调函数)的方式,告诉应用程序。这时,应用程序才会去查询 I/O 操作的结果。 异步 I/O 也是到了 Linux 2.6 才支持的功能,并且在很长时间里都处于不完善的状态,比如 glibc 提供的异步 I/O 库,就一直被社区诟病。同时,由于异步 I/O 跟我们的直观逻辑不太一样,想要使用的话,一定要小心设计,其使用难度比较高。 工作模型优化 了解了 I/O 模型后,请求处理的优化就比较直观了。 使用 I/O 多路复用后,就可以在一个进程或线程中处理多个请求,其中,又有下面两种不同的工作模型。 第一种,主进程 + 多个 worker 子进程,这也是最常用的一种模型。这种方法的一个通用工作模式就是:主进程执行 bind() + listen() 后,创建多个子进程;然后,在每个子进程中,都通过 accept() 或 epoll_wait() ,来处理相同的套接字。 比如,最常用的反向代理服务器 Nginx 就是这么工作的。它也是由主进程和多个 worker 进程组成。主进程主要用来初始化套接字,并管理子进程的生命周期;而 worker 进程,则负责实际的请求处理。我画了一张图来表示这个关系。 这里要注意,accept() 和 epoll_wait() 调用,还存在一个惊群的问题。换句话说,当网络 I/O 事件发生时,多个进程被同时唤醒,但实际上只有一个进程来响应这个事件,其他被唤醒的进程都会重新休眠。 其中,accept() 的惊群问题,已经在 Linux 2.6 中解决了; 而 epoll 的问题,到了 Linux 4.5 ,才通过 EPOLLEXCLUSIVE 解决。 为了避免惊群问题, Nginx 在每个 worker 进程中,都增加一个了全局锁(accept_mutex)。这些 worker 进程需要首先竞争到锁,只有竞争到锁的进程,才会加入到 epoll 中,这样就确保只有一个 worker 子进程被唤醒。 不过,根据前面 CPU 模块的学习,你应该还记得,进程的管理、调度、上下文切换的成本非常高。那为什么使用多进程模式的 Nginx ,却具有非常好的性能呢? 这里最主要的一个原因就是,这些 worker 进程,实际上并不需要经常创建和销毁,而是在没任务时休眠,有任务时唤醒。只有在 worker 由于某些异常退出时,主进程才需要创建新的进程来代替它。 当然,你也可以用线程代替进程:主线程负责套接字初始化和子线程状态的管理,而子线程则负责实际的请求处理。由于线程的调度和切换成本比较低,实际上你可以进一步把 epoll_wait() 都放到主线程中,保证每次事件都只唤醒主线程,而子线程只需要负责后续的请求处理。 第二种,监听到相同端口的多进程模型。在这种方式下,所有的进程都监听相同的接口,并且开启 SO_REUSEPORT 选项,由内核负责将请求负载均衡到这些监听进程中去。这一过程如下图所示。 由于内核确保了只有一个进程被唤醒,就不会出现惊群问题了。比如,Nginx 在 1.9.1 中就已经支持了这种模式。 不过要注意,想要使用 SO_REUSEPORT 选项,需要用 Linux 3.9 以上的版本才可以。 C1000K 基于 I/O 多路复用和请求处理的优化,C10K 问题很容易就可以解决。不过,随着摩尔定律带来的服务器性能提升,以及互联网的普及,你并不难想到,新兴服务会对性能提出更高的要求。 很快,原来的 C10K 已经不能满足需求,所以又有了 C100K 和 C1000K,也就是并发从原来的 1 万增加到 10 万、乃至 100 万。从 1 万到 10 万,其实还是基于 C10K 的这些理论,epoll 配合线程池,再加上 CPU、内存和网络接口的性能和容量提升。大部分情况下,C100K 很自然就可以达到。 那么,再进一步,C1000K 是不是也可以很容易就实现呢?这其实没有那么简单了。 首先从物理资源使用上来说,100 万个请求需要大量的系统资源。比如, 假设每个请求需要 16KB 内存的话,那么总共就需要大约 15 GB 内存。 而从带宽上来说,假设只有 20% 活跃连接,即使每个连接只需要 1KB/s 的吞吐量,总共也需要 1.6 Gb/s 的吞吐量。千兆网卡显然满足不了这么大的吞吐量,所以还需要配置万兆网卡,或者基于多网卡 Bonding 承载更大的吞吐量。 其次,从软件资源上来说,大量的连接也会占用大量的软件资源,比如文件描述符的数量、连接状态的跟踪(CONNTRACK)、网络协议栈的缓存大小(比如套接字读写缓存、TCP 读写缓存)等等。 最后,大量请求带来的中断处理,也会带来非常高的处理成本。这样,就需要多队列网卡、中断负载均衡、CPU 绑定、RPS/RFS(软中断负载均衡到多个 CPU 核上),以及将网络包的处理卸载(Offload)到网络设备(如 TSO/GSO、LRO/GRO、VXLAN OFFLOAD)等各种硬件和软件的优化。 C1000K 的解决方法,本质上还是构建在 epoll 的非阻塞 I/O 模型上。只不过,除了 I/O 模型之外,还需要从应用程序到 Linux 内核、再到 CPU、内存和网络等各个层次的深度优化,特别是需要借助硬件,来卸载那些原来通过软件处理的大量功能。 C10M 显然,人们对于性能的要求是无止境的。再进一步,有没有可能在单机中,同时处理 1000 万的请求呢?这也就是 C10M 问题。 实际上,在 C1000K 问题中,各种软件、硬件的优化很可能都已经做到头了。特别是当升级完硬件(比如足够多的内存、带宽足够大的网卡、更多的网络功能卸载等)后,你可能会发现,无论你怎么优化应用程序和内核中的各种网络参数,想实现 1000 万请求的并发,都是极其困难的。 究其根本,还是 Linux 内核协议栈做了太多太繁重的工作。从网卡中断带来的硬中断处理程序开始,到软中断中的各层网络协议处理,最后再到应用程序,这个路径实在是太长了,就会导致网络包的处理优化,到了一定程度后,就无法更进一步了。 要解决这个问题,最重要就是跳过内核协议栈的冗长路径,把网络包直接送到要处理的应用程序那里去。这里有两种常见的机制,DPDK 和 XDP。 第一种机制,DPDK,是用户态网络的标准。它跳过内核协议栈,直接由用户态进程通过轮询的方式,来处理网络接收。 说起轮询,你肯定会下意识认为它是低效的象征,但是进一步反问下自己,它的低效主要体现在哪里呢?是查询时间明显多于实际工作时间的情况下吧!那么,换个角度来想,如果每时每刻都有新的网络包需要处理,轮询的优势就很明显了。比如: 在 PPS 非常高的场景中,查询时间比实际工作时间少了很多,绝大部分时间都在处理网络包; 而跳过内核协议栈后,就省去了繁杂的硬中断、软中断再到 Linux 网络协议栈逐层处理的过程,应用程序可以针对应用的实际场景,有针对性地优化网络包的处理逻辑,而不需要关注所有的细节。 此外,DPDK 还通过大页、CPU 绑定、内存对齐、流水线并发等多种机制,优化网络包的处理效率。 第二种机制,XDP(eXpress Data Path),则是 Linux 内核提供的一种高性能网络数据路径。它允许网络包,在进入内核协议栈之前,就进行处理,也可以带来更高的性能。XDP 底层跟我们之前用到的 bcc-tools 一样,都是基于 Linux 内核的 eBPF 机制实现的。 XDP 的原理如下图所示: 你可以看到,XDP 对内核的要求比较高,需要的是 Linux 4.8 以上版本,并且它也不提供缓存队列。基于 XDP 的应用程序通常是专用的网络应用,常见的有 IDS(入侵检测系统)、DDoS 防御、 cilium 容器网络插件等。 总结 C10K 问题的根源,一方面在于系统有限的资源;另一方面,也是更重要的因素,是同步阻塞的 I/O 模型以及轮询的套接字接口,限制了网络事件的处理效率。Linux 2.6 中引入的 epoll ,完美解决了 C10K 的问题,现在的高性能网络方案都基于 epoll。 从 C10K 到 C100K ,可能只需要增加系统的物理资源就可以满足;但从 C100K 到 C1000K ,就不仅仅是增加物理资源就能解决的问题了。这时,就需要多方面的优化工作了,从硬件的中断处理和网络功能卸载、到网络协议栈的文件描述符数量、连接状态跟踪、缓存队列等内核的优化,再到应用程序的工作模型优化,都是考虑的重点。 再进一步,要实现 C10M ,就不只是增加物理资源,或者优化内核和应用程序可以解决的问题了。这时候,就需要用 XDP 的方式,在内核协议栈之前处理网络包;或者用 DPDK 直接跳过网络协议栈,在用户空间通过轮询的方式直接处理网络包。 当然了,实际上,在大多数场景中,我们并不需要单机并发 1000 万的请求。通过调整系统架构,把这些请求分发到多台服务器中来处理,通常是更简单和更容易扩展的方案。 本篇文章为转载内容。原文链接:https://blog.csdn.net/qq_23864697/article/details/114626793。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-04-11 18:25:52
261
转载
转载文章
...以参考代码仓库的说明文档,喜欢的朋友可以转评赞给一个,点个收藏不丢失,下面呢我介绍一下基本构建思路; 1、关于项目中使用tsx 要想项目中运行tsx,我们就得考虑到tsx语法糖编译的问题,这里就得用到@vitejs/plugin-vue-jsx插件,详细用法参考github文档,安装后,在vite的plugin中直接调用即可; import { defineConfig } from 'vite'import vue from '@vitejs/plugin-vue'import vueJsx from '@vitejs/plugin-vue-jsx'// https://vitejs.dev/config/export default defineConfig({plugins: [vue(), vueJsx()]}) 2、安装tailwindcss 关于tailwindcss + vite方案,它的官网有了很友好的方案,这块大家按部就班的安装就够了,没有多少复杂度,参考地址,选择tailwindcss主要是它提供了一些快速样式,比如padding、margin、background等,如果我们项目是后台管理系统,tailwindcss会大大降低我们写css样式的工作,大家可以去学习一波在项目中用起来,熟悉了以后就觉得他是在是太方便了。 这里不做用法的介绍,就推荐一个vscode插件Tailwind CSS IntelliSense,安装后,在项目中我们就可以只能提示,如下所示: 3、关于eslint + prettier 代码统一规范 关于代码规范,一般小一点公司不太会做这方面的工程化配置,但是eslint等这些代码规范工具,会让我们团队的代码更规范,风格更统一,团队协作更加方便,我简单说一下配置eslint及prettier的办法 (1)首先安装eslint工具库 pnpm add eslint -D pnpm eslint --init (2)安装外部的语法eslint规范及import校验规范 选择对应的项目内容,这里我的项目用到(vue, typescript,browser)这个,当然有这个还不够,我们需要安装如下两个工具包 pnpm add eslint-plugin-import // 主要对于es与typescript import 路径的一个eslint校验 pnpm add eslint-config-airbnb-base // 这个是airbnb出的一套eslint语法规范的工具库,如果自己公司没有对应的代码规范,这个是很实用的一套 (3)编写vue3相关的规范 项目中我们用到的是eslint-plugin-vue这个vue代码校验规范工具,里面有很多内容及配置项功能,我们这里推荐大家在配置代码规范,可以参考官方的说明文档,链接放在这里; (4)安装和配置prettier 这个相对来讲比较简单一些,我们直接安装pnpm add eslint-plugin-prettier eslint-config-prettier prettier -D,这里我们需要注意的是prettier与eslint冲突问题; 上面是配置时候的基本流程,最终结果我将eslintrc文件及package.json文件放到这里,有需要的朋友,可以直接copy一份去配置,毕竟这个配置很臭很长,深入学习感觉又没有太大必要(23333~) {"name": "vue-tsx-template","private": true,"version": "0.0.0","scripts": {"dev": "vite","build": "vue-tsc --noEmit && vite build","preview": "vite preview","fix": "eslint --fix --ext .js,.jsx,.tsx,.vue src && prettier "},"dependencies": {"vue": "^3.2.25"},"devDependencies": {"@typescript-eslint/eslint-plugin": "^5.23.0","@typescript-eslint/parser": "^5.23.0","@vitejs/plugin-vue": "^2.3.3","@vitejs/plugin-vue-jsx": "^1.3.10","autoprefixer": "^10.4.7","eslint": "^8.15.0","eslint-config-airbnb-base": "^15.0.0","eslint-config-prettier": "^8.5.0","eslint-plugin-import": "^2.26.0","eslint-plugin-prettier": "^4.0.0","eslint-plugin-vue": "^8.7.1","postcss": "^8.4.13","prettier": "^2.6.2","sass": "^1.51.0","tailwindcss": "^3.0.24","typescript": "^4.5.4","vite": "^2.9.9","vue-eslint-parser": "^9.0.1","vue-tsc": "^0.34.7"} } 下面是.eslintrc.js文件 module.exports = {env: {browser: true,es2021: true,node: true,// 处理 defineProps 报错'vue/setup-compiler-macros': true,},extends: ['eslint:recommended','airbnb-base','prettier','plugin:prettier/recommended','plugin:vue/vue3-recommended','plugin:@typescript-eslint/recommended','plugin:import/recommended','plugin:import/typescript',],parser: 'vue-eslint-parser',parserOptions: {ecmaVersion: 'latest',parser: '@typescript-eslint/parser',sourceType: 'module',},plugins: ['vue', '@typescript-eslint'],rules: {// 防止prettier与eslint冲突'prettier/prettier': 'error',// eslint-plugin-import es module导入eslint规则配置,旨在规避拼写错误问题'import/no-unresolved': 0,'import/extensions': ['error',{js: 'never',jsx: 'never',ts: 'never',tsx: 'never',json: 'always',},],// 使用导出的名称作为默认属性(主要用作导出模块内部有 default, 和直接导出两种并存情况下,会出现default.proptry 这种问题从在的情况)'import/no-named-as-default-member': 0,'import/order': ['error', { 'newlines-between': 'always' }],// 导入确保是否在首位'import/first': 0,// 如果文件只有一个导出,是否开启强制默认导出'import/prefer-default-export': 0,'import/no-extraneous-dependencies': ['error',{devDependencies: [],optionalDependencies: false,},],/ 关于typescript语法校验 参考文档: https://www.npmjs.com/package/@typescript-eslint/eslint-plugin/'@typescript-eslint/no-extra-semi': 0,// 是否禁止使用any类型'@typescript-eslint/no-explicit-any': 0,// 是否对于null情况做非空断言'@typescript-eslint/no-non-null-assertion': 0,// 是否对返回值类型进行定义校验'@typescript-eslint/explicit-function-return-type': 0,'@typescript-eslint/member-delimiter-style': ['error', { multiline: { delimiter: 'none' } }],// 结合eslint 'no-use-before-define': 'off',不然会有报错,需要关闭eslint这个校验,主要是增加了对于type\interface\enum'no-use-before-define': 'off','@typescript-eslint/no-use-before-define': ['error'],'@typescript-eslint/explicit-module-boundary-types': 'off','@typescript-eslint/no-unused-vars': ['error',{ignoreRestSiblings: true,varsIgnorePattern: '^_',argsIgnorePattern: '^_',},],'@typescript-eslint/explicit-member-accessibility': ['error', { overrides: { constructors: 'no-public' } }],'@typescript-eslint/consistent-type-imports': 'error','@typescript-eslint/indent': 0,'@typescript-eslint/naming-convention': ['error',{selector: 'interface',format: ['PascalCase'],},],// 不允许使用 var'no-var': 'error',// 如果没有修改值,有些用const定义'prefer-const': ['error',{destructuring: 'any',ignoreReadBeforeAssign: false,},],// 关于vue3 的一些语法糖校验// 超过 4 个属性换行展示'vue/max-attributes-per-line': ['error',{singleline: 4,},],// setup 语法糖校验'vue/script-setup-uses-vars': 'error',// 关于箭头函数'vue/arrow-spacing': 'error','vue/html-indent': 'off',},} 4、加入单元测试 单元测试,根据自己项目体量及重要性而去考虑是否要增加,当然单测可以反推一些组件 or 方法的设计是否合理,同样如果是一个稳定的功能在加上单元测试,这就是一个很nice的体验; 我们单元测试是基于jest来去做的,具体安装单测的办法如下,跟着我的步骤一步步来; 安装jest单测相关的依赖组件库 pnpm add @testing-library/vue @testing-library/user-event @testing-library/jest-dom @types/jest jest @vue/test-utils -D 安装完成后,发现还需要安装前置依赖 @testing-library/dom @vue/compiler-sfc我们继续补充 安装babel相关工具,用ts写的单元测试需要转义,具体安装工具如下pnpm add @babel/core babel-jest @vue/babel-preset-app -D,最后我们配置babel.config.js module.exports = {presets: ['@vue/app'],} 配置jest.config.js module.exports = {roots: ['<rootDir>/test'],testMatch: [// 这里我们支持src目录里面增加一些单层,事实上我并不喜欢这样做'<rootDir>/src//__tests__//.{js,jsx,ts,tsx}','<rootDir>/src//.{spec,test}.{js,jsx,ts,tsx}',// 这里我习惯将单层文件统一放在test单独目录下,不在项目中使用,降低单测文件与业务组件模块混合在一起'<rootDir>/test//.{spec,test}.{js,jsx,ts,tsx}',],testEnvironment: 'jsdom',transform: {// 此处我们单测没有适用vue-jest方式,项目中我们江永tsx方式来开发,所以我们如果需要加入其它的内容// '^.+\\.(vue)$': '<rootDir>/node_modules/vue-jest','^.+\\.(js|jsx|mjs|cjs|ts|tsx)$': '<rootDir>/node_modules/babel-jest',},transformIgnorePatterns: ['<rootDir>/node_modules/','[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$','^.+\\.module\\.(css|sass|scss|less)$',],moduleFileExtensions: ['ts', 'tsx', 'vue', 'js', 'jsx', 'json', 'node'],resetMocks: true,} 具体写单元测试的方法,可以参考项目模板中的组件单元测试写法,这里不做过多的说明; 5、封装axios请求库 这里呢其实思路有很多种,如果有自己的习惯的封装方式,就按照自己的思路,下面附上我的封装代码,简短的说一下我的封装思路: 1、基础的请求拦截、相应拦截封装,这个是对于一些请求参数格式化处理等,或者返回值情况处理 2、请求异常、错误、接口调用成功返回结果错误这些错误的集中处理,代码中请求就不再做trycatch这些操作 3、请求函数统一封装(代码中的 get、post、axiosHttp) 4、泛型方式定义请求返回参数,定义好类型,让我们可以在不同地方使用有良好的提示 import type { AxiosRequestConfig, AxiosResponse } from 'axios'import axios from 'axios'import { ElNotification } from 'element-plus'import errorHandle from './errorHandle'// 定义数据返回结构体(此处我简单定义一个比较常见的后端数据返回结构体,实际使用我们需要按照自己所在的项目开发)interface ResponseData<T = null> {code: string | numberdata: Tsuccess: booleanmessage?: string[key: string]: any}const axiosInstance = axios.create()// 设定响应超时时间axiosInstance.defaults.timeout = 30000// 可以后续根据自己http请求头特殊邀请设定请求头axiosInstance.interceptors.request.use((req: AxiosRequestConfig<any>) => {// 特殊处理,后续如果项目中有全局通传参数,可以在这儿做一些处理return req},error => Promise.reject(error),)// 响应拦截axiosInstance.interceptors.response.use((res: AxiosResponse<any, any>) => {// 数组处理return res},error => Promise.reject(error),)// 通用的请求方法体const axiosHttp = async <T extends Record<string, any> | null>(config: AxiosRequestConfig,desc: string,): Promise<T> => {try {const { data } = await axiosInstance.request<ResponseData<T>>(config)if (data.success) {return data.data}// 如果请求失败统一做提示(此处我没有安装组件库,我简单写个mock例子)ElNotification({title: desc,message: ${data.message || '请求失败,请检查'},})} catch (e: any) {// 统一的错误处理if (e.response && e.response.status) {errorHandle(e.response.status, desc)} else {ElNotification({title: desc,message: '接口异常,请检查',})} }return null as T}// get请求方法封装export const get = async <T = Record<string, any> | null>(url: string, params: Record<string, any>, desc: string) => {const config: AxiosRequestConfig = {method: 'get',url,params,}const data = await axiosHttp<T>(config, desc)return data}// Post请求方法export const post = async <T = Record<string, any> | null>(url: string, data: Record<string, any>, desc: string) => {const config: AxiosRequestConfig = {method: 'post',url,data,}const info = await axiosHttp<T>(config, desc)return info} 请求错误(状态码错误相关提示) import { ElNotification } from 'element-plus'function notificat(message: string, title: string) {ElNotification({title,message,})}/ @description 获取接口定义 @param status {number} 错误状态码 @param desc {string} 接口描述信息/export default function errorHandle(status: number, desc: string) {switch (status) {case 401:notificat('用户登录失败', desc)breakcase 404:notificat('请求不存在', desc)breakcase 500:notificat('服务器错误,请检查服务器', desc)breakdefault:notificat(其他错误${status}, desc)break} } 6、关于vue-router 及 pinia 这两个相对来讲简单一些,会使用vuex状态管理,上手pinia也是很轻松的事儿,只是更简单化了、更方便了,可以参考模板项目里面的用法example,这里附上router及pinia配置方法,路由守卫,大家可以根据项目的要求再添加 import type { RouteRecordRaw } from 'vue-router'import { createRouter, createWebHistory } from 'vue-router'// 配置路由const routes: Array<RouteRecordRaw> = [{path: '/',redirect: '/home',},{name: 'home',path: '/home',component: () => import('page/Home'),},]const router = createRouter({routes,history: createWebHistory(),})export default router 针对与pinia,参考如下: import { createPinia } from 'pinia'export default createPinia() 在入口文件将router和store注入进去 import { createApp } from 'vue'import App from './App'import store from './store/index'import './style/index.css'import './style/index.scss'import 'element-plus/dist/index.css'import router from './router'// 注入全局的storeconst app = createApp(App).use(store).use(router)app.mount('app') 说这些比较枯燥,建议大家去github参考项目说明文档,下载项目,自己过一遍,喜欢的朋友收藏点赞一下,如果喜欢我构建好的项目给个star不丢失,谢谢各位看官的支持。 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_37764929/article/details/124860873。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-10-05 12:27:41
117
转载
转载文章
...丰富,包括视频、免费文档、在线实验、社区以及专家课程(收费) AWS的考试包括助理级和专家级,并且分别针对架构师、开发与运维人员 助理架构师考试主要针对:设计、实施部署、数据安全、故障排除等4个方面进行考核 AWS的架构师考试重点需要掌握7大“云设计架构”如:弹性原则、最小授权原则等等,熟悉这些非常有助于答题(就好比当初考车的文科一样,是有规律可循的) 多动手非常有助于通过考试,同时也是熟练掌握的不二法宝 助理架构师考试,建议考生拥有6个月AWS实战经验 专家级架构师考试,建议考生拥有2年的实战经验 2. 概述 2.1 AWS的服务列表概览 2.2 需要确定好自己的定位与方向 包括三个维度: - 什么行业 – (移动?视频?互联网?企业?金融?) - 解决什么问题 – 大规模分发?大数据?混合网络? - 使用哪些服务 – 虚拟主机?虚拟网络和安全?hadoop集群?数据仓库? 2.3 学习方法是以赛代练(步步实践,边学边用) 首先【观看自学视频】 然后听取【在线课堂】 理论差不多有,开始【动手实验室】(15个免费实验) 深入了解需要【详细查看文档】建议至少先从FAQ阅读,可以缩短很长时间 利用【免费AWS套餐】注意平时的理解和学习 再进行高级实验 需要了解各个服务之间的关联等,【听取讲师指导课程】,就可以高层次的了解服务内容 参加认证考试 2.4 AWS导师课程分类和级别 人员分类:解决方案师、开发人员、系统操作人员 课程分类:入门级、基础级、高级、专项 3. AWS认证的背景信息 3.1 认证的类型 助理级 – 助理架构师 – 助理开发人员 – 助理系统管理员 专家级 – 专家架构师 – 专家开发运维 认证共有5个,如果要参加专家级认证必须先通过助理级认证,其中“专家开发运维(devops)”的认证则通过任意(开发 or 运维)的助理级认证即可 3.2 获得认证后的收益? 对个人 – 可以证明个人在AWS平台上具备设计、部署和管理高可用、低成本、安全应用的能力 – 在工作上或社区中得到尊重和认可 – 可以把认证放到简历中,linkedin中整合了AWS认证徽章 对企业雇主 – 具备AWS上服务和工具的使用的认可 – 客户认可,降低AWS项目实施风险 – 增加客户满意度 3.3 再认证模式 因为AWS的服务在更新,因此每两年要重新认证(证件的有效期2年),再次参加考试时,题目、时间将会更少,且认证费用更低 3.4 助理架构师认证的知识领域 四大知识域 1 设计:高可用、高效率、可容错低、可扩展的系统 2 实施和部署:强调部署操作能力 3 数据安全性:在部署操作时,始终保持数据保存和传输的安全 4 排除故障:在系统出现问题时,可以快速找到问题并解决问题 知识权重 - 设计:60%的题目 - 实施和部署:10%的题目 - 数据安全:20%的题目 - 排除故障:10%的题目 PS:考试不会按照上面的次序、考试不会注明考试题目的分类 3.5 认证过程 需要在网上注册,找到距离家里比较近的地方考试(考点) 到了现场需要携带身份证,证明自己 并不允许带手机入场 证件上必须有照片 签署NDA保证不会泄露考题 考试中心的电脑中考试(80分钟,55个考题) 考试后马上知道分数和是否通过(不会看到每道题目是否正确) 通过后的成绩、认证证书等将发到email邮箱中 3.6 考试机制 助理级别考试的重点是:单一服务和小规模的组合服务的掌握程度 所有题目都是选择题(多选或单选) 不惩罚打错,所以留白没意义,可以猜一个 55道题 可以给不确定的题目打标签,没提交前都可以回来改答案 3.7 题目示例 单选题 多选题(会告诉你有多少个答案) 汇总查看答案以及mark(标记) 4 AWS架构的7大设计原则 4.1 松耦合 松耦合是容错、运维自动扩容的基础,在设计上应该尽量减少模块间的依赖性,将不会成为未来应用调整、发展的阻碍 松耦合模式的情况 不要标示(依赖)特定对象,依赖特定对象耦合性将非常高 – 使用负载均衡器 – 域名解析 – 弹性IP – 可以动态找到配合的对象,为松耦合带来方便,为应用将来的扩展带来好处 不要依赖其他模块的正确处理或及时的处理 – 使用尽量使用异步的处理,而不是同步的(SQS可以帮到用户) 4.2 模块出错后工作不会有问题 问问某个模块出了问题,应用会怎么样? 在设计的时候,在出了问题会有影响的模块,进行处理,建立自动恢复性 4.3 实现弹性 在设计上,不要假定模块是正常的、始终不变的 – 可以配合AutoScaling、EIP和可用区AZ来满足 允许模块的失败重启 – 无状态设计比有状态设计好 – 使用ELB、云监控去检测“实例”运行状态 有引导参数的实例(实现自动配置) – 例如:加入user data在启动的时候,告知它应该做的事情 在关闭实例的时候,保存其配置和个性化 – 例如用DynamoDB保存session信息 弹性后就不会为了超配资源而浪费钱了 4.4 安全是整体的事,需要在每个层面综合考虑 基础架构层 计算/网络架构层 数据层 应用层 4.5 最小授权原则 只付于操作者完成工作的必要权限 所有用户的操作必须授权 三种类型的权限能操作AWS – 主账户 – IAM用户 – 授权服务(主要是开发的app) 5 设计:高可用、高效率、可容错、可扩展的系统 本部分的目标是设计出高可用、高效率低成本、可容错、可扩展的系统架构 - 高可用 – 了解AWS服务自身的高可靠性(例如弹性负载均衡)—-因为ELB是可以多AZ部署的 – 用好这些服务可以减少可用性的后顾之忧 - 高效率(低成本) – 了解自己的容量需求,避免超额分配 – 利用不同的价格策略,例如:使用预留实例 – 尽量使用AWS的托管服务(如SNS、SQS) - 可容错 – 了解HA和容错的区别 – 如果说HA是结果,那么容错则是保障HA的一个重要策略 – HA强调系统不要出问题,而容错是在系统出了问题后尽量不要影响业务 - 可扩展性 – 需要了解AWS哪些服务自身就可以扩展,例如SQS、ELB – 了解自动伸缩组(AS) 运用好 AWS 7大架构设计原则的:松耦合、实现弹性 6 实施和部署设计 本部分的在设计的基础上找到合适的工具来实现 对比第一部分“设计”,第一章主要针对用什么,而第二章则讨论怎么用 主要考核AWS云的核心的服务目录和核心服务,包括: 计算机和网络 – EC2、VPC 存储和内容分发 – S3、Glacier 数据库相关分类 – RDS 部署和管理服务 – CloudFormation、CloudWatch、IAM 应用服务 – SQS、SNS 7 数据安全 数据安全的基础,是AWS责任共担的安全模型模型,必须要读懂 数据安全包括4个层面:基础设施层、计算/网络层、数据层、应用层 - 基础设施层 1. 基础硬件安全 2. 授权访问、流程等 - 计算/网络层 1. 主要靠VPC保障网络(防护、路由、网络隔离、易管理) 2. 认识安全组和NACLs以及他们的差别 安全组比ACL多一点,安全组可以针对其他安全组,ACL只能针对IP 安全组只允许统一,ACL可以设置拒绝 安全组有状态!很重要(只要一条入站规则通过,那么出站也可以自动通过),ACL没有状态(必须分别指定出站、入站规则) 安全组的工作的对象是网卡(实例)、ACL工作的对象是子网 认识4种网关,以及他们的差别 共有4种网关,支撑流量进出VPC internet gatway:互联网的访问 virtual private gateway:负责VPN的访问 direct connect:负责企业直连网络的访问 vpc peering:负责VPC的peering的访问 数据层 数据传输安全 – 进入和出AWS的安全 – AWS内部传输安全 通过https访问API 链路的安全 – 通过SSL访问web – 通过IP加密访问VPN – 使用直连 – 使用OFFLINE的导入导出 数据的持久化保存 – 使用EBS – 使用S3访问 访问 – 使用IAM策略 – 使用bucket策略 – 访问控制列表 临时授权 – 使用签名的URL 加密 – 服务器端加密 – 客户端加密 应用层 主要强调的是共担风险模型 多种类型的认证鉴权 给用户在应用层的保障建议 – 选择一种认证鉴权机制(而不要不鉴权) – 用安全的密码和强安全策略 – 保护你的OS(如打开防火墙) – 用强壮的角色来控制权限(RBAC) 判断AWS和用户分担的安全中的标志是,哪些是AWS可以控制的,那些不能,能的就是AWS负责,否则就是用户(举个例子:安全组的功能由AWS负责—是否生效,但是如何使用是用户负责—自己开放所有端口跟AWS无关) AWS可以保障的 用户需要保障的 工具与服务 操作系统 物理内部流程安全 应用程序 物理基础设施 安全组 网络设施 虚拟化设施 OS防火墙 网络规则 管理账号 8 故障排除 问题经常包括的类型: - EC2实例的连接性问题 - 恢复EC2实例或EBS卷上的数据 - 服务使用限制问题 8.1 EC2实例的连接性问题 经常会有多个原因造成无法连接 外部VPC到内部VPC的实例 – 网关(IGW–internet网关、VPG–虚拟私有网关)的添加问题 – 公司网络到VPC的路由规则设置问题 – VPC各个子网间的路由表问题 – 弹性IP和公有IP的问题 – NACLs(网络访问规则) – 安全组 – OS层面的防火墙 8.2 恢复EC2实例或EBS卷上的数据 注意EBS或EC2没有任何强绑定关系 – EBS是可以从旧实例上分离的 – 如有必要尽快做 将EBS卷挂载到新的、健康的实例上 执行流程可以针对恢复没有工作的启动卷(boot volume) – 将root卷分离出来 – 像数据一样挂载到其他实例 – 修复文件 – 重新挂载到原来的实例中重新启动 8.3 服务使用限制问题 AWS有很多软性限制 – 例如AWS初始化的时候,每个类型的EBS实例最多启动20个 还有一些硬性限制例如 – 每个账号最多拥有100个S3的bucket – …… 别的服务限制了当前服务 – 例如无法启动新EC2实例,原因可能是EBS卷达到上限 – Trusted Advisor这个工具可以根据服务水平的不同给出你一些限制的参考(从免费试用,到商业试用,和企业试用的建议) 常见的软性限制 公共的限制 – 每个用户最多创建20个实例,或更少的实例类型 – 每个区域最多5个弹性ip – 每个vpc最多100个安全组 – 最多20个负载均衡 – 最多20个自动伸缩组 – 5000个EBS卷、10000个快照,4w的IOPS和总共20TB的磁盘 – …更多则需要申请了 你不需要记住限制 – 知道限制,并保持数值敏感度就好 – 日后遇到问题时可以排除掉软限制的相关的问题 9. 总结 9.1 认证的主要目标是: 确认架构师能否搜集需求,并且使用最佳实践,在AWS中构建出这个系统 是否能为应用的整个生命周期给出指导意见 9.2 希望架构师(助理或专家级)考试前的准备: 深度掌握至少1门高级别语言(c,c++,java等) 掌握AWS的三份白皮书 – aws概览 – aws安全流程 – aws风险和应对 – 云中的存储选项 – aws的架构最佳实践 按照客户需求,使用AWS组件来部署混合系统的经验 使用AWS架构中心网站了解更多信息 9.3 经验方面的建议 助理架构师 – 至少6个月的实际操作经验、在AWS中管理生产系统的经验 – 学习过AWS的基本课程 专家架构师 – 至少2年的实际操作经验、在AWS中管理多种不同种类的复杂生产系统的经验(多种服务、动态伸缩、高可用、重构或容错) – 在AWS中执行构建的能力,架构的高级概念能力 9.4 相关资源 认证学习的资源地址 - 可以自己练习,模拟考试需要付费的 接下来就去网上报名参加考试 本篇文章为转载内容。原文链接:https://blog.csdn.net/QXK2001/article/details/51292402。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-11-29 22:08:40
271
转载
转载文章
...选择多个项目,或者在文档中选择文本 Shift + Delete -> 无需先将选定项移动到“回收站”,直接将其删除 三、win(windows徽标的简称)相关 win + L -> 锁定电脑 win + D -> 显示和隐藏桌面 win + E -> 打开“文件资源管理器” win + I -> 打开“设置” win + M -> 最小化所有窗口 win + Shift + M -> 将最小化的窗口还原到桌面 win + P -> 选择演示显示模式 win + K -> 打开“连接”快速操作 win + L -> 锁定电脑或切换帐户 win + Tab -> 打开“任务视图” win + R -> 打开运行窗口 四、其他快捷键 End -> 显示活动窗口的底端 Home -> 显示活动窗口的顶端 F11 -> 最大化或最小化活动窗口 五、运行窗口快捷命令 先输入win+ R 本小结转载地址:https://blog.csdn.net/qq_42402854/article/details/93162387 1.calc:启动计算器 2.appwiz.cpl:程序和功能 3.certmgr.msc:证书管理实用程序 4.charmap:启动字符映射表 5.chkdsk.exe:Chkdsk磁盘检查(管理员身份运行命令提示符) 6.cleanmgr: 打开磁盘清理工具 7.cliconfg:SQL SERVER 客户端网络实用工具 8.cmstp:连接管理器配置文件安装程序 9.cmd:CMD命令提示符 10.自动关机命令 Shutdown -s -t 600:表示600秒后自动关机 shutdown -a :可取消定时关机 Shutdown -r -t 600:表示600秒后自动重启 rundll32 user32.dll,LockWorkStation:表示锁定计算机 11.colorcpl:颜色管理,配置显示器和打印机等中的色彩 12.CompMgmtLauncher:计算机管理 13.compmgmt.msc:计算机管理 14.credwiz:备份或还原储存的用户名和密码 15.comexp.msc:打开系统组件服务 16.control:控制面版 17.dcomcnfg:打开系统组件服务 18.Dccw:显示颜色校准 19.devmgmt.msc:设备管理器 20.desk.cpl:屏幕分辨率 21.dfrgui:优化驱动器 Windows 7→dfrg.msc:磁盘碎片整理程序 22.dialer:电话拨号程序 23.diskmgmt.msc:磁盘管理 24.dvdplay:DVD播放器 25.dxdiag:检查DirectX信息 26.eudcedit:造字程序 27.eventvwr:事件查看器 28.explorer:打开资源管理器 29.Firewall.cpl:Windows防火墙 30.FXSCOVER:传真封面编辑器 31.fsmgmt.msc:共享文件夹管理器 32.gpedit.msc:组策略 33.hdwwiz.cpl:设备管理器 34.inetcpl.cpl:Internet属性 35.intl.cpl:区域 36.iexpress:木马捆绑工具,系统自带 37.joy.cpl:游戏控制器 38.logoff:注销命令 39.lusrmgr.msc:本地用户和组 40.lpksetup:语言包安装/删除向导,安装向导会提示下载语言包 41.lusrmgr.msc:本机用户和组 42.main.cpl:鼠标属性 43.mmsys.cpl:声音 44.magnify:放大镜实用程序 45.mem.exe:显示内存使用情况(如果直接运行无效,可以先管理员身份运行命令提示符,在命令提示符里输入mem.exe>d:a.txt 即可打开d盘查看a.txt,里面的就是内存使用情况了。当然什么盘什么文件名可自己决定。) 46.MdSched:Windows内存诊断程序 47.mmc:打开控制台 48.mobsync:同步命令 49.mplayer2:简易widnows media player 50.Msconfig.exe:系统配置实用程序 51.msdt:微软支持诊断工具 52.msinfo32:系统信息 53.mspaint:画图 54.Msra:Windows远程协助 55.mstsc:远程桌面连接 56.NAPCLCFG.MSC:客户端配置 57.ncpa.cpl:网络连接 58.narrator:屏幕“讲述人” 59.Netplwiz:高级用户帐户控制面板,设置登陆安全相关的选项 60.netstat : an(TC)命令检查接口 61.notepad:打开记事本 62.Nslookup:IP地址侦测器 63.odbcad32:ODBC数据源管理器 64.OptionalFeatures:打开“打开或关闭Windows功能”对话框 65.osk:打开屏幕键盘 66.perfmon.msc:计算机性能监测器 67.perfmon:计算机性能监测器 68.PowerShell:提供强大远程处理能力 69.printmanagement.msc:打印管理 70.powercfg.cpl:电源选项 71.psr:问题步骤记录器 72.Rasphone:网络连接 73.Recdisc:创建系统修复光盘 74.Resmon:资源监视器 75.Rstrui:系统还原 76.regedit.exe:注册表 77.regedt32:注册表编辑器 78.rsop.msc:组策略结果集 79.sdclt:备份状态与配置,就是查看系统是否已备份 80.secpol.msc:本地安全策略 81.services.msc:本地服务设置 82.sfc /scannow:扫描错误并复原/windows文件保护 83.sfc.exe:系统文件检查器 84.shrpubw:创建共享文件夹 85.sigverif:文件签名验证程序 86.slui:Windows激活,查看系统激活信息 87.slmgr.vbs -dlv :显示详细的许可证信息 88.snippingtool:截图工具,支持无规则截图 89.soundrecorder:录音机,没有录音时间的限制 90.StikyNot:便笺 91.sysdm.cpl:系统属性 92.sysedit:系统配置编辑器 93.syskey:系统加密,一旦加密就不能解开,保护系统的双重密码 94.taskmgr:任务管理器(旧版) 95.TM任务管理器(新版) 96.taskschd.msc:任务计划程序 97.timedate.cpl:日期和时间 98.UserAccountControlSettings用户账户控制设置 99.utilman:辅助工具管理器 100.wf.msc:高级安全Windows防火墙 101.WFS:Windows传真和扫描 102.wiaacmgr:扫描仪和照相机向导 103.winver:关于Windows 104.wmimgmt.msc:打开windows管理体系结构(WMI) 105.write:写字板 106.wscui.cpl:操作中心 107.wuapp:Windows更新 108.wscript:windows脚本宿主设置 六、小结 键盘快捷键会大大提高使用效率,让你在外行面前显得更酷。持续更新中…感谢点赞,评论与转发,谢谢! 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_44168588/article/details/121208530。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-02-01 13:38:26
92
转载
转载文章
...纳入DirectX API中,并在NVIDIA RTX系列显卡上得到广泛应用。通过模拟真实世界的光线行为,光线追踪能够生成更为逼真细腻的光影效果,极大地提升了三维场景的真实感。 此外,针对三维建模与动画制作软件,Blender项目持续进行功能更新,支持多种坐标系统并整合了基于物理的渲染引擎Cycles。用户不仅可以在其中创建复杂的三维模型,还能利用内置的高级着色器进行法线贴图、置换贴图等复杂纹理处理,以及实现PBR材质以满足更高标准的视觉需求。 在理论研究方面,学者们正在深入探讨四元数在图形旋转、插值运算等方面的优化算法,力图挖掘其在实时渲染、虚拟现实和增强现实环境中的潜在价值。一些前沿研究甚至将四元数应用于机器学习与人工智能驱动的动画系统中,以实现更加自然、连贯的动作捕捉与运动预测。 综上所述,无论是实时渲染技术的发展、硬件特性的革新,还是三维设计工具的进步,都在不断推动三维坐标系与几何学在计算机图形学中的实际应用向着更高效、更真实的方向发展。关注这些领域的最新动态和技术成果,无疑将有助于您更好地掌握三维图形编程的未来趋势及其实现方法。
2023-10-24 12:49:42
272
转载
转载文章
...对那些获取抽象类或者接口对象而来的。最常见的匿名内部类View点击事件: //java,匿名内部类的写法 上面这个是java匿名内部类的写法,kotlin没有new关键字,那么kotlin的匿名内部类该怎么写呢? object : View.OnClickListener{ 方法的参数是一个匿名内部类,先写object:,然后写你的参数类型View.OnClickListener{} kotlin还有一个写法lambda 表达式,非常之方便: print( 数据类 在Java中没有专门的数据类,常常是通过JavaBean来作为数据类,但在Kotlin中提供了专门的数据类。 Java public 从上面的例子中可以看到,如果要使用数据类,需要手动写相应的setter/getter方法(尽管IDE也可以批量生成),但是从代码阅读的角度来说,在属性较多的情况下,诸多的seeter/getter方法还是不利于代码的阅读和维护。 Kotlin 在Kotlin中,可以通过关键字data来生成数据类: data 即在class关键字之前添加data关键字即可。编译器会根据主构造函数中的参数生成相应的数据类。自动生成setter/getter、toString、hashCode等方法 要声明一个数据类,需要满足: 主构造函数中至少有一个参数 主构造函数中所有参数需要标记为val或var 数据类不能是抽象、开发、密封和内部的 枚举类 枚举类是一种特殊的类,kotlin可以通过enum class关键字定义枚举类。 枚举类可以实现0~N个接口; 枚举类默认继承于kotlin.Enum类(其他类最终父类都是Any),因此kotlin枚举类不能继承类; 非抽象枚举类不能用open修饰符修饰,因此非抽象枚举类不能派生子类; 抽象枚举类不能使用abstract关键字修饰enum class,抽象方法和抽象属性需要使用; 枚举类构造器只能使用private修饰符修饰,若不指定,则默认为private; 枚举类所有实例在第一行显式列出,每个实例之间用逗号隔开,整个声明以分号结尾; 枚举类是特殊的类,也可以定义属性、方法、构造器; 枚举类应该设置成不可变类,即属性值不允许改变,这样更安全; 枚举属性设置成只读属性后,最好在构造器中为枚举类指定初始值,如果在声明时为枚举指定初始值,会导致所有枚举值(或者说枚举对象)的该属性都一样。 定义枚举类 / 定义一个枚举类 / 枚举类实现接口 枚举值分别实现接口的抽象成员 enum 枚举类统一实现接口的抽象成员 enum 分别实现抽象枚举类抽象成员 enum 委托 委托模式 是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。委托模式是一项基本技巧,许多其他的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式。委托模式使得我们可以用聚合来替代继承。 Java中委托: interface Printer { Kotlin: interface Printer { by表示 p 将会在 PrintImpl 中内部存储, 并且编译器将自动生成转发给 p 的所有 Printer 的方法。 委托属性 有一些常见的属性类型,虽然我们可以在每次需要的时候手动实现它们, 但是如果能够为大家把他们只实现一次并放入一个库会更好。例如包括: 延迟属性(lazy properties): 其值只在首次访问时计算; 可观察属性(observable properties): 监听器会收到有关此属性变更的通知; 把多个属性储存在一个映射(map)中,而不是每个存在单独的字段中。 为了涵盖这些(以及其他)情况,Kotlin 支持 委托属性 。 委托属性的语法是: var : 在 by 后面的表达式是该 委托, 因为属性对应的 get()(和 set())会被委托给它的 getValue() 和 setValue() 方法。 标准委托: Kotlin 标准库为几种有用的委托提供了工厂方法。 延迟属性 Lazy lazy() 接受一个 lambda 并返回一个 Lazy 实例的函数,返回的实例可以作为实现延迟属性的委托:第一次调用 get() 会执行已传递给 lazy() 的 lambda 表达式并记录结果, 后续调用 get() 只是返回记录的结果。例如: val lazyValue: String 可观察属性 Observable Delegates.observable() 接受两个参数:初始值和修改时处理程序(handler)。每当我们给属性赋值时会调用该处理程序(在赋值后执行)。它有三个参数:被赋值的属性、旧值和新值: class User { 如果想拦截赋的新值,并根据你是不是想要这个值来决定是否给属性赋新值,可以使用 vetoable() 取代 observable(),接收的参数和 observable 一样,不过处理程序 返回值是 Boolean 来决定是否采用新值,即在属性被赋新值生效之前 会调用传递给 vetoable 的处理程序。例如: class User { 把属性存在map 中 一个常见的用例是在一个映射(map)里存储属性的值。这经常出现在像解析 JSON 或者做其他“动态”事情的应用中。在这种情况下,你可以使用映射实例自身作为委托来实现委托属性。 例如: class User(map: Map 在上例中,委托属性会从构造函数传入的map中取值(通过字符串键——属性的名称),如果遇到声明的属性名在map 中找不到对应的key 名,或者key 对应的value 值的类型与声明的属性的类型不一致,会抛出异常。 内联函数 当一个函数被声明为inline时,它的函数体是内联的,也就是说,函数体会被直接替换到函数被调用地方 inline函数(内联函数)从概念上讲是编译器使用函数实现的真实代码来替换每一次的函数调用,带来的最直接的好处就是节省了函数调用的开销,而缺点就是增加了所生成字节码的尺寸。基于此,在代码量不是很大的情况下,我们是否有必要将所有的函数定义为内联?让我们分两种情况进行说明: 将普通函数定义为内联:众所周知,JVM内部已经实现了内联优化,它会在任何可以通过内联来提升性能的地方将函数调用内联化,并且相对于手动将普通函数定义为内联,通过JVM内联优化所生成的字节码,每个函数的实现只会出现一次,这样在保证减少运行时开销的同时,也没有增加字节码的尺寸;所以我们可以得出结论,对于普通函数,我们没有必要将其声明为内联函数,而是交给JVM自行优化。 将带有lambda参数的函数定义为内联:是的,这种情况下确实可以提高性能;但在使用的过程中,我们会发现它是有诸多限制的,让我们从下面的例子开始展开说明: inline 假如我们这样调用doSomething: fun main(args: Array<String>) { 上面的调用会被编译成: fun main(args: Array<String>) { 从上面编译的结果可以看出,无论doSomething函数还是action参数都被内联了,很棒,那让我们换一种调用方式: fun main(args: Array<String>) { 上面的调用会被编译成: fun main(args: Array<String>) { doSomething函数被内联,而action参数没有被内联,这是因为以函数型变量的形式传递给doSomething的lambda在函数的调用点是不可用的,只有等到doSomething被内联后,该lambda才可以正常使用。 通过上面的例子,我们对lambda表达式何时被内联做一下简单的总结: 当lambda表达式以参数的形式直接传递给内联函数,那么lambda表达式的代码会被直接替换到最终生成的代码中。 当lambda表达式在某个地方被保存起来,然后以变量形式传递给内联函数,那么此时的lambda表达式的代码将不会被内联。 上面对lambda的内联时机进行了讨论,消化片刻后让我们再看最后一个例子: inline 上面的例子是否有问题?是的,编译器会抛出“Illegal usage of inline-parameter”的错误,这是因为Kotlin规定内联函数中的lambda参数只能被直接调用或者传递给另外一个内联函数,除此之外不能作为他用;那我们如果确实想要将某一个lambda传递给一个非内联函数怎么办?我们只需将上述代码这样改造即可: inline 很简单,在不需要内联的lambda参数前加上noinline修饰符就可以了。 以上便是我对内联函数的全部理解,通过掌握该特性的运行机制,相信大家可以做到在正确的时机使用该特性,而非滥用或因恐惧弃而不用。 Kotlin下单例模式 饿汉式实现 //Java实现 懒汉式 //Java实现 上述代码中,我们可以发现在Kotlin实现中,我们让其主构造函数私有化并自定义了其属性访问器,其余内容大同小异。 如果有小伙伴不清楚Kotlin构造函数的使用方式。请点击 - - - 构造函数 不清楚Kotlin的属性与访问器,请点击 - - -属性和字段 线程安全的懒汉式 //Java实现 大家都知道在使用懒汉式会出现线程安全的问题,需要使用使用同步锁,在Kotlin中,如果你需要将方法声明为同步,需要添加@Synchronized注解。 双重校验锁式 //Java实现 哇!小伙伴们惊喜不,感不感动啊。我们居然几行代码就实现了多行的Java代码。其中我们运用到了Kotlin的延迟属性 Lazy。 Lazy内部实现 public 观察上述代码,因为我们传入的mode = LazyThreadSafetyMode.SYNCHRONIZED, 那么会直接走 SynchronizedLazyImpl,我们继续观察SynchronizedLazyImpl。 Lazy接口 SynchronizedLazyImpl实现了Lazy接口,Lazy具体接口如下: public 继续查看SynchronizedLazyImpl,具体实现如下: SynchronizedLazyImpl内部实现 private 通过上述代码,我们发现 SynchronizedLazyImpl 覆盖了Lazy接口的value属性,并且重新了其属性访问器。其具体逻辑与Java的双重检验是类似的。 到里这里其实大家还是肯定有疑问,我这里只是实例化了SynchronizedLazyImpl对象,并没有进行值的获取,它是怎么拿到高阶函数的返回值呢?。这里又涉及到了委托属性。 委托属性语法是:val/var : by 。在 by 后面的表达式是该 委托, 因为属性对应的 get()(和 set())会被委托给它的 getValue() 和 setValue() 方法。属性的委托不必实现任何的接口,但是需要提供一个 getValue() 函数(和 setValue()——对于 var 属性)。 而Lazy.kt文件中,声明了Lazy接口的getValue扩展函数。故在最终赋值的时候会调用该方法。 internal.InlineOnly 静态内部类式 //Java实现 静态内部类的实现方式,也没有什么好说的。Kotlin与Java实现基本雷同。 补充 在该篇文章结束后,有很多小伙伴咨询,如何在Kotlin版的Double Check,给单例添加一个属性,这里我给大家提供了一个实现的方式。(不好意思,最近才抽出时间来解决这个问题) class SingletonDemo private constructor( 其中关于?:操作符,如果 ?: 左侧表达式非空,就返回其左侧表达式,否则返回右侧表达式。请注意,当且仅当左侧为空时,才会对右侧表达式求值。 Kotlin 智能类型转换 对于子父类之间的类型转换 先看这样一段 Java 代码 public 尽管在 main 函数中,对 person 这个对象进行了类型判断,但是在使用的时候还是需要强制转换成 Student 类型,这样是不是很不智能? 同样的情况在 Kotlin 中就变得简单多了 fun main(args: Array<String>) { 在 Kotlin 中,只要对类型进行了判断,就可以直接通过父类的对象去调用子类的函数了 安全的类型转换 还是上面的那个例子,如果我们没有进行类型判断,并且直接进行强转,会怎么样呢? public static void main(String[] args) { 结果就只能是 Exception in thread "main" java.lang.ClassCastException 那么在 Kotlin 中是不是会有更好的解决方法呢? val person: Person = Person() 在转换操作符后面添加一个 ?,就不会把程序 crash 掉了,当转化失败的时候,就会返回一个 null 在空类型中的智能转换 需要提前了解 Kotlin 类型安全的相关知识(Kotlin 中的类型安全(对空指针的优化处理)) String? = aString 在定义的时候定义成了有可能为 null,按照之前的写法,我们需要这样写 String? = 但是已经进行了是否为 String 类型的判断,所以就一定 不是 空类型了,也就可以直接输出它的长度了 T.()->Unit 、 ()->Unit 在做kotlin开发中,经常看到一些系统函数里,用函数作为参数 public .()-Unit与()->Unit的区别是我们调用时,在代码块里面写this,的时候,两个this代表的含义不一样,T.()->Unit里的this代表的是自身实例,而()->Unit里,this代表的是外部类的实例。 推荐阅读 对 Kotlin 与 Java 编程语言的思考 使用 Kotlin 做开发一个月后的感想 扫一扫 关注我的公众号如果你想要跟大家分享你的文章,欢迎投稿~ 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_39611037/article/details/109984124。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-06-23 23:56:14
472
转载
转载文章
...,可以帮助开发团队和API用户更快定位问题根源,进而提升软件质量及维护效率。 另外,关于何时抛出或捕获异常的讨论也在持续进行中。有文章深度剖析了《Effective C》一书中提出的异常使用准则,并结合实际案例分析了过度使用异常可能导致的性能损耗和代码可读性下降等问题。因此,提倡在编写代码时采用防御性编程策略,如预先检查参数的有效性、合理运用Try-Parse等方法,以减少不必要的异常抛出。 综上所述,随着.NET技术的发展和业界最佳实践的不断演进,深入学习和掌握最新的异常处理技巧,将有助于我们在日常开发工作中构建更为稳定、高效的软件系统。
2023-04-13 13:38:26
60
转载
站内搜索
用于搜索本网站内部文章,支持栏目切换。
知识学习
实践的时候请根据实际情况谨慎操作。
随机学习一条linux命令:
chmod +x script.sh
- 给脚本添加执行权限。
推荐内容
推荐本栏目内的其它文章,看看还有哪些文章让你感兴趣。
2023-04-28
2023-08-09
2023-06-18
2023-04-14
2023-02-18
2023-04-17
2024-01-11
2023-10-03
2023-09-09
2023-06-13
2023-08-07
2023-03-11
历史内容
快速导航到对应月份的历史文章列表。
随便看看
拉到页底了吧,随便看看还有哪些文章你可能感兴趣。
时光飞逝
"流光容易把人抛,红了樱桃,绿了芭蕉。"