首页
关于作者
阅读记录
友链
Search
1
微内核插件架构风格在skywalking agent 上的实践
363 阅读
2
debian 11 安装nginx 并配置端口映射
341 阅读
3
和chatgpt聊设计
307 阅读
4
开始看《金阁寺》
246 阅读
5
github上star的工程分类记录
202 阅读
不知所云
杂记
书籍摘抄
有点技术
Redis
运维
架构
nginx
byzer
尚未分类
程序人生
与AI聊天
登录
/
注册
Search
标签搜索
nginx
redis
byzer
github
运维
mybatis-plus
王猪
累计撰写
25
篇文章
累计收到
3
条评论
首页
栏目
不知所云
杂记
书籍摘抄
有点技术
Redis
运维
架构
nginx
byzer
尚未分类
程序人生
与AI聊天
页面
关于作者
阅读记录
友链
搜索到
24
篇与
的结果
2023-06-28
微内核插件架构风格
微内核插件架构风格关于微内核架构设计,相信大家都有听说过,也有自己的理解。那么微内核是如何被提出来的?微内核在操作系统内核的设计中又有什么作用?关于微内核架构设计,听起来好像是操作系统内核相关的,实际上,每天都在用。Eclipse、IntelliJ IDEA、OSGi、Spring Plugin、SPI等都是插件化的。即便是我们每天都在使用的技术,而且大多数人也都知道,但是它具体的好处在哪儿,如何具体设计,开发?微内核微内核设计其实就是插件体系。我们都知道,操作系统内核诞生得比较早,所以插件化最早被用在内核设计上,于是就有了微内核设计这一称呼。微内核是这样一种内核:它只完成内核不得不完成的功能,包括时钟中断、进程创建与销毁、进程调度、进程间通信,而其他的诸如文件系统、内存管理、设备驱动等都被作为系统进程放到了用户态空间。说白了,微内核是相对于宏内核而言的,像Linux就是典型的宏内核,它除了时钟中断、进程创建与销毁、进程调度、进程间通信外,其他的文件系统、内存管理、输入输出、设备驱动管理都需要内核完成。插件化插件化架构非常简单,就两个核心组件:系统核心(Core System)和插件化组件(Plug-in component)。Core System负责管理各种插件,当然Core System也会包含一些重要功能,如插件注册管理、插件生命周期管理、插件之间的通讯、插件动态替换等。架构特点优点:微内核:核心系统只提供最基本的功能和服务,如资源管理、事件处理和插件管理等。它不处理具体的业务逻辑,而是将业务逻辑委托给插件来处理。插件:插件是独立的模块,包含特定的功能和业务逻辑。它们可以被动态加载和卸载,以实现系统的灵活性和可扩展性。插件可以通过接口或扩展点与核心系统进行通信和交互。插件管理:核心系统负责插件的管理,包括插件的加载、卸载、启动和停止等。它提供了一套机制来管理插件的生命周期,并确保插件之间的隔离和安全性。松耦合:插件之间是松耦合的,它们通过接口或扩展点进行通信,而不是直接依赖于具体的实现。这样可以降低系统的复杂性,并支持插件的替换和升级。可扩展性:通过添加或替换插件,系统可以轻松地扩展新的功能和服务。插件可以根据需求进行定制和配置,以满足不同的业务需求。灵活性:插件的动态加载和卸载使系统具有灵活性。可以根据实际需要启用或禁用插件,以适应不同的运行环境和需求。缺点:复杂性:由于系统的功能被分散到多个插件中,系统的整体复杂性可能会增加。同时,插件之间的协作和通信也需要一定的设计和管理,增加了系统的复杂性和维护成本。性能损耗:插件的扩展和调用可能会引入额外的性能损耗,特别是在插件之间需要频繁的通信和协作时。因此,在设计和实现时需要权衡系统的性能和灵活性。配置和管理:由于插件的存在,系统的配置和管理可能变得更加复杂。需要管理和维护多个插件的配置,确保它们之间的兼容性和正确性。需要确保核心版本与可用的插件版本范围。适用场景微内核插件架构风格适用于以下场景:复杂系统:当系统变得庞大且复杂时,使用微内核插件架构可以将系统分解为多个可独立开发和维护的插件模块,每个插件模块只关注特定的功能领域,降低了系统的复杂性。可扩展性要求高:微内核插件架构允许系统根据需求动态加载和卸载插件模块,使系统具备良好的可扩展性。当系统需要新增功能或者修改功能时,只需要编写或者替换相应的插件模块,而不需要对整个系统进行大规模的修改。定制化需求:微内核插件架构允许用户根据自己的需求选择和组合插件模块,实现定制化的功能。用户可以根据自己的业务场景选择需要的插件模块,而不需要使用系统中的所有功能。多样化的环境:微内核插件架构可以使系统在不同的环境中运行,例如在不同的操作系统、不同的硬件平台或者不同的网络环境中。通过选择不同的插件模块,系统可以适应不同的环境要求。需要注意的是,微内核插件架构虽然具有灵活性和可扩展性,但也会增加系统的复杂性和管理成本。因此,在选择使用微内核插件架构时,需要权衡其带来的优势和劣势,并根据具体的需求和情况做出决策。开源项目有几个知名的开源系统使用了微内核插件架构风格,其中一些包括:Eclipse:Eclipse是一个著名的开源集成开发环境(IDE),它使用了插件架构来支持各种功能和扩展。通过插件,开发者可以根据自己的需求选择安装和使用各种工具和功能。Jenkins:Jenkins是一个流行的持续集成和交付工具,它使用插件架构来支持各种构建、测试和部署任务。Jenkins的插件机制使得用户可以根据需要自定义和扩展其功能。WordPress:WordPress是一个广泛使用的开源内容管理系统(CMS),它使用插件架构来支持各种功能和扩展。通过安装和启用不同的插件,用户可以添加新的功能、样式和工具。Gradle:Gradle是一个灵活的构建工具,它使用插件架构来支持各种构建任务和功能。通过使用不同的插件,开发者可以定制和扩展Gradle的构建过程。SkyWalking:SkyWalking是一个开源的分布式系统追踪和性能监控解决方案,它提供了核心的追踪和监控功能,同时也提供了各种插件来支持不同的应用和框架,例如支持Spring Cloud、Dubbo等。这些系统的共同点是它们都采用了插件架构,使得用户可以根据自己的需求选择和扩展功能,提高系统的灵活性和可扩展性。作为插件开发者作为一个微内核插件架构风格的系统的插件开发人员,以下是一般的插件开发步骤:了解插件机制:首先,你需要深入了解目标系统的插件机制。了解核心接口、扩展点以及插件的生命周期管理等方面的知识。创建插件项目:根据目标系统的插件开发规范,创建一个新的插件项目。这可以是一个独立的代码库或是一个模块。实现插件接口或扩展点:根据目标系统提供的接口或扩展点,实现你的插件逻辑。确保你的插件能够与目标系统进行正确的交互。注册插件:在目标系统的配置文件或注册中心中注册你的插件。这样目标系统在启动时就能够加载并使用你的插件。编译和打包插件:将你的插件编译成可执行的二进制文件或打包成可部署的插件包。确保你的插件能够被目标系统正确加载和使用。部署和测试插件:将你的插件部署到目标系统中,并进行测试以确保插件的功能和性能符合预期。编写文档和示例:为你的插件编写文档和示例,以便其他开发人员能够理解和使用你的插件。提供清晰的说明和示例可以帮助其他人更好地使用你的插件。总结起来,插件开发的关键是理解目标系统的插件机制,并按照规范实现插件接口或扩展点。同时,良好的文档和示例也是插件开发中不可忽视的一部分,它们能够帮助其他开发人员更好地使用你的插件。作为设计者设计和开发一个微内核插件架构风格的系统需要经过以下步骤:定义核心接口:首先,你需要定义系统的核心接口,这些接口代表系统的基本功能和服务。这些接口应该是抽象和通用的,以便于插件的实现和扩展。核心接口应该包括系统的主要组件,例如数据存储、身份验证、日志记录等。实现核心功能:根据定义的核心接口,实现系统的核心功能。这些功能应该是基本的、通用的,并且不依赖于具体的插件实现。核心功能的实现应该是稳定和可靠的,以便于插件的集成和扩展。定义插件接口:根据系统的需求,定义插件接口。插件接口应该定义插件需要实现的方法和功能,以及与核心功能的交互方式。插件接口应该是抽象和通用的,以便于不同的插件实现。实现插件:根据定义的插件接口,实现插件。每个插件应该实现特定的功能或服务,并且可以独立于其他插件进行开发和部署。插件的实现应该符合插件接口的要求,并且可以与核心功能进行交互。插件管理:实现插件管理机制,用于加载、启用和禁用插件。插件管理应该能够动态地加载和卸载插件,以便于系统的灵活性和扩展性。插件管理可以使用反射、依赖注入或其他适合的机制来实现。集成测试和优化:进行集成测试,确保核心功能和插件的正确性和稳定性。根据测试结果进行优化,修复可能存在的问题和性能瓶颈。文档和示例:编写文档和示例,以便于其他开发人员理解和使用系统。文档应该包括系统的架构、核心接口和插件接口的说明,以及插件的开发和集成指南。请注意,微内核插件架构风格的系统设计和开发需要对系统的需求和架构有一定的理解和经验。同时,需要考虑插件的安全性、性能和兼容性等方面的问题。最简开发一个微内核插件系统定义插件接口定义一个接口Plugin,包含三个方法,需要插件去实现。/** * 插件 */ public interface Plugin { /** * 执行前 */ void doBefore(); /** * 执行 * @param context 上下文 */ void doExecute(Context context); /** * 执行后 */ void doAfter(); }定义一个插件说明,用于描述插件。import java.util.Objects; public class PluginType { String name; String version; Class clazz; public PluginType(String name, String version, Class clazz) { this.name = name; this.version = version; this.clazz = clazz; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; PluginType that = (PluginType) o; return Objects.equals(name, that.name) && Objects.equals(version, that.version); } @Override public int hashCode() { return Objects.hash(name, version); } @Override public String toString() { return "[name='" + name + '\'' + ", version='" + version + '\'' + ']'; } }定义一个插件注册器,用于存放插件。import java.util.HashMap; import java.util.Map; /** * 插件注册 */ public class PluginRegister { /** * 存储加载的插件 */ private static final Map<PluginType, Plugin> PLUGIN_MAP = new HashMap<>(16); /** * 注册插件 * @param type 类型 * @param plugin 插件 */ public static void registerPlugin(PluginType type, Plugin plugin) { System.out.println("PluginRegister Loading Plugin " + type); PLUGIN_MAP.put(type, plugin); } public static Plugin getPlugin(PluginType type) { Plugin plugin = PLUGIN_MAP.get(type); if (null == plugin) { throw new RuntimeException("plugin not exist " + type); } return plugin; } }实现插件实现插件接口,并进行注册。public class Plugin2 implements Plugin { @Override public void doBefore() { System.out.println("loading plugin2"); } @Override public void doExecute(Context context) { System.out.println("executing plugin2"); } @Override public void doAfter() { System.out.println("finish plugin2"); } static { PluginType type = new PluginType("plugin2", "1.0.1", Plugin2.class); PluginRegister.registerPlugin(type, new Plugin2()); } }实现核心调用插件核心根据接收到的参数,调用所需插件。public class CoreStarter { public static void main(String[] args) throws ClassNotFoundException { System.out.println("core starting"); System.out.println("core do other businesses"); System.out.println("core deal plugin config"); String pluginType = args[0]; String pluginVersion = args[1]; String className = args[2]; // Class.forName(className) 会触发static{}代码块 Class clazz = Class.forName(className); PluginType type = new PluginType(pluginType, pluginVersion, clazz); System.out.println("core get plugin type" + type); Plugin plugin = PluginRegister.getPlugin(type); System.out.println("core load plugin " + plugin.getClass().toString()); Context context = new Context(); plugin.doBefore(); plugin.doExecute(context); plugin.doAfter(); System.out.println("core do other businesses"); } }启动参数:plugin2 1.0.1 Plugin2启动后控制台输出:core starting core do other businesses core deal plugin config PluginRegister Loading Plugin [name='plugin2', version='1.0.1'] core get plugin type[name='plugin2', version='1.0.1'] core load plugin class Plugin2 loading plugin2 executing plugin2 finish plugin2 core do other businesses Process finished with exit code 0core在Class.forName(className) 时jvm会将Plugin加载到内存中,并且会触发静态代码块static{}。由插件自行注册到PluginRegister#PLUGIN_MAP 中。这个工程十分精简,所需的类不超过10个,但是实现了核心能够根据参数去调用插件的生命周期的方法这一核心架构思想。工程目录工程已上传 micro-plugin
2023年06月28日
60 阅读
0 评论
0 点赞
2023-06-21
202306中心级opsMaster运维比赛总结
202306中心级opsMaster运维比赛总结考察能力一共出了7道题,大致考察了java反编译、oracle分区索引、redis、nginx、网络命令、日志分析、内存、磁盘、抓包分析我用还记得住的点记录一下。内存超出本题考查了 JVM 参数,需要对JVM 有一定的了解。java 进程A 访问java 进程B,若正常页面会返回答案,异常则返回内存空间不足。进入服务器发现 进程B 占用内存3g, 立即重启,重启报错,空间不足。显然它还是占用了过大的空间。JVM启动参数添加 -Xmx512m 。限制内存使用512m, 启动解决问题。java -Xmx512m processB.jaroracle分区索引失效本题考查了oracle分区索引失效的解决方案。访问页面,报错 ORA-XXXX,某分区索引失效。反编译,获取数据库连接串,通过plsql 连接, 重建该分析索引,或者直接删除分区索引均可。可以先看看失效的索引有哪些:SELECT INDEX_OWNER, INDEX_NAME, PARTITION_NAME, STATUS FROM DBA_IND_PARTITIONS WHERE STATUS='UNUSABLE';因为我们知道了索引名、表名,也可以直接查ALL_INDEXESSELECT * FROM ALL_INDEXES WHERE owner = '用户名' AND TABLE_NAME = '表名';下一步删除索引即可,当然,如果该索引在主键约束中,则还需加一步。-- 去除主键索引 ALTER TABLE 表名 DROP CONSTRAINT 主键约束名; -- 删除索引 DROP INDEX 索引名;解决问题后,则获得答案。ORACLE 分区索引为啥会失效呢? 一般都是DDL操作导致的,但是DML也是有可能的。REDIS GET 命令报错本题考查了redis 运维相关的知识,如何禁用一个命令。这次在页面上显示报错 redis get 命令错误。而get命令是redis基础命令,不应有错。通过反编译jar包,在linux上通过redis-cli 执行get 发现的确报错。通过 ps -ef | grep redis 查看到redis进程,但貌似没指定配置文件。直接kill,再去/usr/local/redis/bin重启redis-server,发现的确没报错了,但是也没数据。显然,这步操作十分的冒失了,相当于重启之后数据文件位置指定不对,它其实是有配置文件启动的。通过find / -name redis.conf 查找到了3个配置文件,通过路径上的6379猜测应该是它,则用它重启redis,重现了该问题。然后在配置文件中,发现了rename get '' 将get 命令禁用了,将其注释并重启则解决问题。其实,还有一种方法,进到服务器时,不将redis进程kill掉,用lsof找到它的数据路径,直接用新的配置文件,将数据路径指向其去启动即可。生产上,像keys、 flushdb、 flushall、 config 等命令都是被运维要求禁用的,都是通过rename来实现。当然,redis 7 之后的acl控制可以有其他方法。nginx 403 forbidden考察nginx 配置文件当页面访问403后,首先想到的是将项目文件的权限改正,让nginx有权限读。后发现仍403,打开配置文件未发现异常,但是它有include conf.d文件夹中的配置文件,在其中找到了 deny all 配置,删除其即可完成访问。网络命令、磁盘本题综合考察提干说X端口的python服务用于接收另一台机器的请求,备份日志。但是不知其IP,但是给出了服务器账号和密码。通过 netstat -ano|grep 端口号, 则可以发现和本机建立连接的IP。 登录后发现其启动的python脚本中提示是磁盘空间不足。通过df -h 查看到该日志目录挂载的磁盘的确空间不足,通过 rm -rf * 完成删除即可。抓包分析wireshark的应用,网络知识题目说某位老师(xxxxx)忘记了内管账号的密码,但是有正常登录时的网络包,找出他的密码。打开题目给定的网络包,直接先过滤一手 http 协议。在备注中可以看到有些POST 访问xxx/inner/xxx的报文,打开一看的确是请求登录的报文。通过TCP流追踪可以发现,登录报错都是400返回,找到数个成功的是200返回码,当然,还需要注意该老师的工号要对上。日志分析考察awk,sort等一系列命令的运用。在给定的logs目录下有 system.out.log.1 - system.out.log.100 这100个文件,让我们找出访问接口次数最多的接口,它在哪个文件中被访问的最多。所以其实一共有两步,先找到该接口,再找到该接口在哪个文件中出现次数最多。# $3 是每行分割后接口所在的列 awk '{print $3}' logs/system.out.log.* | sort | uniq -c | sort -rn | head -n 10 1111 /api/login 231 /api/test 1 /actuator/info ...(demo)接下来,我们再找出它在哪个文件中个数最多cd logs # $1 是grep 输出的第一列,文件名 grep "/api/login" system.out.log.* | awk -F ':' '{print $1}' | sort | uniq -c | sort -nr | head -n 10 653 system.out.log.21 251 system.out.log.2 37 system.out.log.56 ...(demo)那么最多的就是system.out.log.21。对于不长时间运维的的确挺难的,我们知道命令也没在时限内做出来。
2023年06月21日
88 阅读
1 评论
2 点赞
2023-06-21
github上star的工程分类记录
github上star的工程分类记录记录2023年6月在github上发现的有趣的工程。主要在于ETL相关的OLAP数据源、查询引擎用于借鉴。还有风靡一时的openai相关的代理、机器人项目。文档类a-picture-is-worth-a-1000-words 用动漫图解释算法、数据结构、AI等概念知识。终端zellij 有智能提示的终端。chatGptpoe-openai-proxy 把poe代理成openai的接口。便于使用免费的poe进行chat ai。moco-ai-clientAndroid 应用,集成了ChatGPT, Bing Chat, Bard, Poechathub 集成了所有aiChatALL集成了所有aiChatGPT-Midjourney🍭 一键拥有你自己的 ChatGPT+Midjourney 网页服务ETLseatunnelSeaTunnel专注于数据集成和数据同步,主要解决数据集成领域的常见问题pinotApache Pinot 是一个实时分布式 OLAP 数据存储,旨在以低延迟提供可扩展的实时分析。它可以从批处理数据源(例如 Hadoop HDFS、Amazon S3、Azure ADLS、谷歌云存储)以及流数据源(例如 Apache Kafka)中摄取。datahubDataHub 是现代数据堆栈的开源元数据平台。trinoTrino 是一个用于大数据分析的快速分布式 SQL 查询引擎。搜索OpenSearchOpenSearch 是社区驱动的 Elasticsearch 和 Kibana 的开源分支JAVAretrofitHTTP客户端dynamic-tp轻量级动态线程池,内置监控告警功能,集成三方中间件线程池管理LOGgraylog2-server 开源日志管理系统图床picx🏞️ PicX 是一款基于 GitHub API 开发的图床工具,提供图片上传托管、生成图片链接和常用图片工具箱服务。
2023年06月21日
202 阅读
0 评论
0 点赞
2023-06-15
如何免费拥有个人图床(存储于github)
PicX这是一个免费的网页版本的图床,存储仅需一个github token。可以在github token 中新建一个。即可拥有自己的图床。配置PicX配置 中填入Token,手动配置一下。选择刚新建的一个仓库,放在根目录下:上传图片上传图片 可以选中文件上传,也可以已经在剪切板中,直接ctrl + v 粘贴即可。(所以我们可以截图,然后立马去粘贴!)配置cdn、复制方式配置后,复制出来的路径就是cdn的,格式可以是html通用的,也可以是markdown的。<img src="https://cdn.staticaly.com/gh/HuiWang1995/picBed@master/blog-image.uckmv7jsexs.jpg" alt="blog-image" />备份因为存储都在github上,上传都是用github api的方式,所以所有文件都可以通过git进行备份,可以fork到gitee上,或者clone到本地,都是可以的~
2023年06月15日
82 阅读
0 评论
0 点赞
2023-06-15
byzer大数据集群配置变化
byzer大数据集群配置变化因cdh升级为cdp后,原本的小集群被大佬收回去到大集群中了,byzer所用的集群配置就需要发生修改。另外,因为大集群的权限配置更为严格,byzer修改配置时就会遇到这些问题。配置下载从 cloudera manager 中下载hadoop、yarn、hive的配置文件,并覆盖到byzer engine 配置的spark的conf下。修改hostscdp集群中的主机都以主机名作为配置,故需要修改/etc/hosts 文件,把对应的主机名与IP映射补上。安装用户切换为hive用户原先部署在/root/apps目录中,则使用root启动,byzer会直接使用root去做hive的连接。以下几个问题是在调整用户时遇到的。byzer启动失败Permission denied: user=root(具体用户名),access=WRITE, inode="/user":hdfs:supergroup:drwxr-xr-x这是因为这个用户没权限,需要授权,或者换个用户byzer 任务执行失败Permission denied: user=root(具体用户名),access=READ_EXECUTE, inode="/user/xxx/xxx":hive:hive:drwxr-x--x也是因为权限不足导致的。byzer 启动无限输出日志INFO Client: Application report for application_xxxxxxx_xxxx (state:ACCEPTED)是任务提交到了yarn,但是未被执行,属于资源分配不足,或者已经有人用这个用户把资源用完了。可以暂时的byzer部署目录下的 conf/byzer.properties.override 中修改配置将占用资源减小尝试重启。
2023年06月15日
76 阅读
0 评论
0 点赞
1
2
3
4
5
浙公网安备 33020502001051号
浙ICP备2023015387号-1