首页 文章 精选 留言 我的

精选列表

搜索[快速],共10000篇文章
优秀的个人博客,低调大师

ulthon_admin v2.0.19 发布,PHP 后台快速开发框架

本次发行版中,优化了底层建设的代码,并实现了一个强大的特性(对我来说如此): 从数据库生成数据库迁移代码 用法 什么是数据库迁移工具 ulthon_admin标准的安装流程是使用数据库迁移工具进行安装,他不仅可以安装到mysql数据库,也支持sqlite,sqlserver等其它数据库。 具体用法参考文档: https://www.kancloud.cn/manual/thinkphp6_0/1118028 但一般而言,我们开发中不会从写迁移代码开始,而是直接使用顺手的数据库工具(Dbeaver、Navcat等)设计数据库,然后在开发中修修补补。 这并没有什么不妥,但是如果你做的是一个标准产品,需要经常执行安装和更新,需要给多个客户部署时,就会感到吃力。 遇到这种情况,你只能从一个数据库导出,再导入到另一个数据库,反反复复的操作。还有可能不知道哪个是最新的,哪个需要更新,哪个更新到哪个版本了。 另一方面,如果数据库丢失了,而你手里又没有及时备份,那么也是很头疼的事。 数据库迁移工具就是为了解决以上种种问题的,比如我们需要新建一张test_goods数据表,我们可以使用数据库迁移工具,写出这样的代码: <?php use think\migration\Migrator; use think\migration\db\Column; class TestGoods extends Migrator { public function change() { $table = $this->table('test_goods') ->setComment('商品列表') ->addColumn('cate_id', 'biginteger', ['limit' => '20', 'signed' => '0', 'null' => '0', 'default' => '0', 'comment' => '分类ID {relation} (table:mall_cate,relationBindSelect:title)',]) ->addColumn('title', 'char', ['limit' => '20', 'null' => '0', 'default' => '', 'comment' => '商品名称',]) ....... ->addColumn('detail', 'text', ['null' => '1', 'comment' => '详情',]) ->addIndex('uid', ['unique' => true]) ->addIndex('detail', ['type' => 'fulltext']) ->addIndex('cate_id') ->create(); } } 然后运行命令: php think migrate:run 此时这张表就出现在我们的数据库了,至于其他的表,并不会覆盖或丢失。 这样有很多好处: 数据库跟随版本库存储不会丢失 没有反复多余的导出数据库 可以安装到“任何数据库” 任何标准产品都可以任意运行该命令用于升级数据库 但是我们开发的时候,不会直接写数据迁移工具,而是从设计表开始。如果我们需要数据库迁移工具,就只能照着现在的数据表写迁移工具,这是以前的做法,也只能这样做。但是现在不一样了,通过一行命令可以一键生成数据库迁移的代码。就像生成curd那样。 现在按照我们的介绍看看怎么用吧。 使用 我们先用自己喜欢的方式设计出一张表。 -- admin_demo_ultho.ul_test_goods definition CREATE TABLE `ul_test_goods` ( `id` int(11) NOT NULL AUTO_INCREMENT, `cate_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '分类ID {relation} (table:mall_cate,relationBindSelect:title)', `title` char(20) NOT NULL DEFAULT '' COMMENT '商品名称', `logo` char(255) NOT NULL COMMENT '商品logo {image}', `images` text NOT NULL COMMENT '商品图片 {images}', `describe` text NOT NULL COMMENT '商品描述 {editor}', `total_stock` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '总库存', `sort` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '排序', `status` int(1) unsigned NOT NULL DEFAULT '0' COMMENT '状态 {radio} (0:正常,1:禁用)', `cert_file` varchar(100) NOT NULL COMMENT '合格证 {file}', `verfiy_file` text NOT NULL COMMENT '检测报告 {files}', `remark` char(255) NOT NULL DEFAULT '' COMMENT '备注说明', `create_time` int(11) unsigned NOT NULL DEFAULT '0', `update_time` int(11) unsigned NOT NULL DEFAULT '0', `delete_time` int(11) unsigned NOT NULL DEFAULT '0', `publish_time` int(10) unsigned NOT NULL COMMENT '发布日期 {date} (date)', `sale_time` bigint(20) unsigned NOT NULL COMMENT '售卖日期 {date} (datetime)', `intro` varchar(100) NOT NULL COMMENT '简介 {textarea}', `time_status` smallint(5) unsigned NOT NULL COMMENT '秒杀状态 {select} (0:未参加,1:已开始,3:已结束)', `is_recommend` tinyint(4) NOT NULL COMMENT '是否推荐 {switch} (0:不推荐,1:推荐)', `shop_type` varchar(100) NOT NULL COMMENT '商品类型 {checkbox} (taobao:淘宝,jd:京东)', `tag` varchar(100) NOT NULL COMMENT '商品标签 {table} (table:mall_tag,type:checkbox,valueField:id,fieldName:title)', `tag_backup` varchar(100) DEFAULT NULL COMMENT '商品标签(单选) {table} (table:mall_tag,type:radio,valueField:id,fieldName:title)', `from_area` varchar(100) NOT NULL COMMENT '产地 {city} (name-province:0,code:0)', `store_city` varchar(100) NOT NULL DEFAULT '山东省/临沂市' COMMENT '仓库 {city} (level:city)', `tag_input` varchar(100) NOT NULL COMMENT '商品标签 (输入) {tag}', `uid` varchar(100) NOT NULL COMMENT '唯一id', `price` decimal(10,2) DEFAULT NULL COMMENT '价格', `detail` longtext COMMENT '详情', PRIMARY KEY (`id`), UNIQUE KEY `ul_test_goods_uid_IDX` (`uid`) USING BTREE, KEY `cate_id` (`cate_id`) USING BTREE, FULLTEXT KEY `ul_test_goods_detail_IDX` (`detail`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='商品列表'; 面对这样一张数据表,如果我们要对照写出数据库迁移工具的代码,会很费事,而且很容易就写错了。 但现在时代变了,只需要一行命令 php think curd:migrate -t test_goods 此时会在数据库迁移工具的工作目录下生成一个文件: database\migrations\20220905222557_test_goods.php 这跟使用官方的生成方式一致 此时会直接生成开头那样的数据库迁移代码。 结尾 可能你没用过数据库迁移工具,那么目前可能无法引起你的兴趣,(建议使用),如果你正在使用,那么这个命令绝对能给你带来极大的便利。甚至可以让那些拥有几十个数据表的项目,也能轻松地使用数据库迁移工具来安装了。 ulthon_admin正在积极维护,拥有极高的定制性,支持依赖裁剪,精简代码,欢迎使用。

优秀的个人博客,低调大师

JeeSite 4.4.1 发布,无用户限制,Spring Boot 快速开发平台

被封闭的这段时间深感从业不易,为支持小微企业发展,今后发布的所有社区版将全线解除用户数限制。 愿疫情早日散去,山河无恙,人间皆安。🌞🌞 升级内容 升级 Spring Boot 2.5.13、Shiro 1.9.0、其它工具等等 新增 Spring configuration metadata yml 配置信息友好提示 新增 是否启用默认 Servlet 映射(启用后可访问 webapp 下的静态资源访问) 新增 支持Spring Boot带减号的 key 写法,自动转换为驼峰格式 新增 BPM 查询全部待办、已办流程数据接口 新增 OAuth2 state 缓存集群共享 新增 CacheUtils exists 方法 优化 便捷脚本、Docker脚本优化、Maven配置优化 优化 CacheUtils 不存储当前用户信息,防止流程标题生成串用户 优化 多线程,Redis 消息监听线程池、用户缓存清理线程池、消息推送线程池,避免高并发情况下太多的线程问题。 优化 服务器监控磁盘列表,隐藏一些不必要的盘符 优化 访问日志的控制台日志信息输出 优化 Cloud网关路由简化配置 修正 ie10下用户缓存问题修改头像未刷新 修正 sqlserver下流程名称排序错误 可视化数据大屏升级 Avue-data v2.3 无用户数限制,无在线人数限制 升级方法 修改pom.xml文件中的jeesite-parent版本号为4.4.1-SNAPSHOT 如果你导入了jeesite-common源码项目,请与git上的代码进行同步 如果你导入了jeesite-module-core源码项目,请与git上的代码进行同步 如果你是跨版本升级,请注意每一个版本的升级方法,业务上有调整的地方进行修改 Shiro 升级到 1.9.0 shiroFilter 方法 getInstance() 替换为 getObject() 执行root/package.bat(sh)打包脚本,强制更新依赖即可 了解更多 JeeSite 官网地址:http://jeesite.com JeeSite 在线文档:http://docs.jeesite.com JeeSite 演示地址:http://demo.jeesite.com JeeSiteVue演示地址:http://vue.jeesite.com

优秀的个人博客,低调大师

零代码快速集成AGC崩溃服务-xamarin框架-iOS

华为AGC的崩溃服务支持跨平台,按照文档整理了个Xamarin插件集成的文档,有需要的开发者可以参考。 环境配置和项目设置 1.安装Xamarin环境 主要是先安装visual studio for MAC,然后安装Mobile development with .NET,具体可以参考Xamarin环境搭建。 2.AGC创建项目工程,并且开通华为分析服务。 这部分是基本操作,可以参见创建项目和开通华为分析 3.集成AGC Xamarin NuGet包 点击创建的项目工程,右键选择”Manage NuGet Packages” 选择对应的包后安装: 继续添加HA包,注意需要选择1.2.0.300版本: 4.添加Json文件到项目目录下 5.将“Build Action”设置为“BundleResource”。 6.设置应用包名。 7.配置免费预配证书 如果没有申请付费证书,可以使用免费证书,具体参见: https://developer.huawei.com/consumer/cn/doc/development/AppGallery-connect-Guides/agc-get-started-xamarin#h2-1617333170516-2 集成实现 1.布局界面设计 双击main.storyboard拉起Xcode创建3个按键“MakeCrash”,” CatchException”,” CustomReport”。 2.代码调用 编辑 ViewController.cs 文件, 调用 AGCCrash.GetSharedInstance.TestIt 制造一次崩溃事件,调用 AGCCrash.GetSharedInstance.SetUserId 自定义用户标识,调用 AGCCrash.GetSharedInstance.SetCustomKey 自定义键值对,调用 AGCCrash.GetSharedInstance.Log 自定义日志级别,调用 AGCCrash.GetSharedInstance. RecordException 产生并记录一次非严重异常。 usingSystem; usingUIKit; usingHuawei.Agconnect.Crash; usingFoundation; namespacecrashios0512 { publicpartialclassViewController:UIViewController { publicViewController(IntPtrhandle):base(handle) { } publicoverridevoidViewDidLoad() { base.ViewDidLoad(); //Performanyadditionalsetupafterloadingtheview,typicallyfromanib. } publicoverridevoidDidReceiveMemoryWarning() { base.DidReceiveMemoryWarning(); //Releaseanycacheddata,images,etcthataren'tinuse. } partialvoidMakeCrash(UIKit.UIButtonsender) { AGCCrash.GetSharedInstance().TestIt(); } partialvoidCatchException(UIKit.UIButtonsender) { AGCCrash.GetSharedInstance().RecordError(newFoundation.NSError()); } partialvoidCustomReport(UIKit.UIButtonsender) { AGCCrash.GetSharedInstance().SetUserId("testuser"); AGCCrash.GetSharedInstance().Log("defaultinfolevel"); AGCCrash.GetSharedInstance().SetCustomValue(newNSString("test"),"thisisstringvalue"); AGCCrash.GetSharedInstance().LogWithLevel(AGCCrashLogLevel.Warning,"thisiswarningloglevel"); AGCCrash.GetSharedInstance().SetCustomValue(newNSNumber(123),"thisisnumber"); } } } 崩溃报告查看 集成完后点击按键制造崩溃和非严重异常,并产生自定义报告,可以在AGC页面查看 1.崩溃概览 2.问题概览 3.查看崩溃详情堆栈 4.查看自定义键值对 5.查看自定义日志级别 6.查看自定义用户标识 欲了解更多详情,请参见: 1、华为AGC 崩溃服务文档:https://developer.huawei.com/consumer/cn/doc/development/AppGallery-connect-Guides/agc-crash-introduction 2、华为AGC-崩溃服务codelab:https://developer.huawei.com/consumer/cn/codelabsPortal/carddetails/CrashService-iOS 更多精彩内容,请见华为开发者官方论坛→https://developer.huawei.com/consumer/cn/forum/home?ha_source=sanfang

优秀的个人博客,低调大师

在docker中快速使用各个版本的PostgreSQL数据库

安装概述 PG安装方法很多,和MySQL类似,给用户提供很大的选择空间。如:RPM包安装(在线、离线)、源码编译安装、系统自带、二进制、NDB安装等。 https://www.postgresql.org/ https://yum.postgresql.org/rpmchart.php https://yum.postgresql.org/11/redhat/rhel-6-x86_64/repoview/postgresqldbserver11.group.html https://www.postgresql.org/ftp/source/ 打开 PostgreSQL 官网 https://www.postgresql.org/,点击菜单栏上的 Download ,可以看到这里包含了很多平台的安装包,包括 Linux、Windows、Mac OS等 。 各个安装包:https://www.postgresql.org/ftp/source/ Linux 我们可以看到支持 Ubuntu 和 Red Hat 等各个平台,点击具体的平台链接,即可查看安装方法: 点击上图中的 file browser,我们还能下载 PostgreSQL 最新的源码。 Docker直接使用 Docker Hub的官网地址:https://hub.docker.com/_/postgres GitHub的地址:https://github.com/docker-library/postgres -- 拉取所有镜像 docker pull postgres:9.4 docker pull postgres:9.6 docker pull postgres:10 docker pull postgres:11 docker pull postgres:12 docker pull postgres:13 docker pull postgres:13.3 -- 创建各个版本的Docker容器 docker rm -f lhrpg94 lhrpg96 lhrpg10 lhrpg11 lhrpg12 lhrpg13 docker run --name lhrpg94 -h lhrpg94 -d -p 54321:5432 -e POSTGRES_PASSWORD=lhr -e TZ=Asia/Shanghai postgres:9.4 docker run --name lhrpg96 -h lhrpg96 -d -p 54322:5432 -e POSTGRES_PASSWORD=lhr -e TZ=Asia/Shanghai postgres:9.6 docker run --name lhrpg10 -h lhrpg10 -d -p 54323:5432 -e POSTGRES_PASSWORD=lhr -e TZ=Asia/Shanghai postgres:10 docker run --name lhrpg11 -h lhrpg11 -d -p 54324:5432 -e POSTGRES_PASSWORD=lhr -e TZ=Asia/Shanghai postgres:11 docker run --name lhrpg12 -h lhrpg12 -d -p 54325:5432 -e POSTGRES_PASSWORD=lhr -e TZ=Asia/Shanghai postgres:12 docker run --name lhrpg13 -h lhrpg13 -d -p 54326:5432 -e POSTGRES_PASSWORD=lhr -e TZ=Asia/Shanghai postgres:13 docker run --name lhrpg133 -h lhrpg133 -d -p 54327:5432 -e POSTGRES_PASSWORD=lhr -e TZ=Asia/Shanghai postgres:13.3 -- docker直接登陆 docker exec -it lhrpg133 psql -U postgres -d postgres -- 本地登陆 docker exec -it lhrpg133 bash su - postgres psql -- 远程登陆 psql -U postgres -h 192.168.66.35 -d postgres -p54327 -- 从Postgresql 9.2开始,还可以使用URI格式进行远程连接:psql postgresql://myuser:mypasswd@myhost:5432/mydb psql postgresql://postgres:lhr@192.168.66.35:54327/postgres 其中-h参数指定服务器地址,默认为127.0.0.1,默认不指定即可,-d指定连接之后选中的数据库,默认也是postgres,-U指定用户,默认是当前用户,-p 指定端口号,默认是’5432’,其它更多的参数选项可以执行: ./bin/psql —help 查看。 C:\Users\lhrxxt>psql -U postgres -h 192.168.66.35 -d postgres -p54327 Password for user postgres: psql (13.3) Type 'help' for help. postgres=# select version(); version ------------------------------------------------------------------------------------------------------------------ PostgreSQL 13.3 (Debian 13.3-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit (1 row) postgres=# \l List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges -----------+----------+----------+-------------------+-------------------+----------------------- postgres | postgres | UTF8 | Chinese_China.936 | Chinese_China.936 | template0 | postgres | UTF8 | Chinese_China.936 | Chinese_China.936 | =c/postgres + | | | | | postgres=CTc/postgres template1 | postgres | UTF8 | Chinese_China.936 | Chinese_China.936 | =c/postgres + | | | | | postgres=CTc/postgres (3 rows) postgres=# CREATE DATABASE lhrdb WITH OWNER=postgres ENCODING='UTF-8'; CREATE DATABASE postgres=# \c lhrdb You are now connected to database 'lhrdb' as user 'postgres'. lhrdb=# lhrdb=# create table student ( lhrdb(# id integer not null, lhrdb(# name character(32), lhrdb(# number char(5), lhrdb(# constraint student_pkey primary key (id) lhrdb(# ); CREATE TABLE lhrdb=# lhrdb=# \d student Table 'public.student' Column | Type | Collation | Nullable | Default --------+---------------+-----------+----------+--------- id | integer | | not null | name | character(32) | | | number | character(5) | | | Indexes: 'student_pkey' PRIMARY KEY, btree (id) lhrdb=# lhrdb=# INSERT INTO student (id, name, number) VALUES (1, '张三', '1023'); INSERT 0 1 lhrdb=# SELECT * FROM student WHERE id=1; id | name | number ----+------------------------------------+-------- 1 | 张三 | 1023 (1 row) 是不是很方便呢。 安装配置完成。

优秀的个人博客,低调大师

Strategy Analytics:尽管组件短缺,5G仍在快速增长

6月2日消息,根据市场调研机构Strategy Analytics发布的最新报告显示,2020年,尽管发生了新冠肺炎疫情,但用于蜂窝用户设备的无线电组件市场仍在增长,并将持续增长到2025年。 据报告作者、射频和无线组件主管Christopher Taylor称:“尽管出现了疫情,射频组件收入,包括基带处理器和射频前端(RFFE)在2020年达到历史高点。我们预测,到2025年,蜂窝无线电组件市场将以每年8%的速度增长。在设备发货量增长停滞之后,为了帮助应对5G日益增加的无线电复杂性,RFFE组件供应商继续开发具有更多功能的封装模块系统,允许公司在每次设计胜利中捕获更多RFFE内容,同时使原始设备制造商更容易设计和组装手机。” 手机组件技术副总监Sravan Kundojjala补充道:“持续的半导体短缺可能会持续到2022年,这证实了强劲的潜在需求。不过,手机厂商面临供应限制,可能无法在今年充分发挥手机销售潜力。包括台积电、联华电子、GlobalFoundries、中芯国际、三星代工厂和复合半导体代工厂在内的半导体代工厂都在尽快提高产能。” Strategy Analytics预测,对sub-6和mmWave 5G射频组件的强劲需求,以及智能手机以外新的5G机遇,将推动未来几年蜂窝无线组件的显著增长。

优秀的个人博客,低调大师

Microsoft Edge 浏览器将支持快速启动和标签睡眠

在今天的 Microsoft 年度 Build 大会上,微软宣布了其 Edge 浏览器即将发布的 91 版本的一些新功能。这些功能都不是大改动,但对其用户来说可以充分提高使用体验。 一个新功能是 "启动加速",它允许 Edge 几乎立即启动。Microsoft 实现该功能的方式很直接。当用户启动Windows 设备时,会简单地加载一些核心的 Edge 进程,所以当 Edge 真正启动时可以迅速完成。而且据 Microsoft 表示,这并不会对用户的 Windows 10 启动时间有太大的影响。 另一个新功能是 "睡眠标签",它可以让用户的 edge 标签页进入睡眠状态,这样它们就不会占用不必要的内存和 CPU 周期。Microsoft 在12月首次宣布它正在测试这项功能。据当时的 Edge 开发者表示,睡眠标签与不睡眠的标签相比,平均仅使用 37% 的CPU,且可以减少 32% 的内存使用,并有助于改善电池寿命。值得注意的是,Google 的 Chrome 浏览器,与 Edge 共享大部分底层技术,也具有限制资源使用的工具,包括所谓的 "标签冻结"。

优秀的个人博客,低调大师

vn.py快速入门7 - 历史数据回测优化

策略已经写好了,下一步就是历史回测:把历史上的价格数据(K线或者Tick),推送给策略去运行交易逻辑,并把策略产生的交易记录下来,最后分析这些回测的交易记录,从而来判断该策略的潜在盈利能力。 在开始之前,先来讲几个量化策略研究中(不管是否用vn.py),需要记住的几条重要原则: 所有量化程序的回测功能,永远都只能尽量接近实盘交易中的各项细节,而无法做到100%一样,关键点在于误差的大小(是否能容忍); 回测效果好的策略,并不能代表实盘交易就一定盈利,可能存在交易成本误差、参数过度拟合、逻辑有未来函数或者市场特征变化(Regime Switch)等原因; 回测效果烂的策略,实盘交易基本可以保证会更烂,绝对不要有侥幸心理。 准备历史数据 要跑历史数据回测,第一步自然就是要先准备好历史数据。这里我们以国内期货数据为例,使用米筐的RQData来下载获取。 RQData目前提供30天的免费试用权限,网站申请非常方便。前往RQData主页 找到上图中的“免费试用”按钮,点击进去后: 根据自己的实际情况填写相应的注册信息,邀请码点击那个白色小问号图标,可以看到没有邀请码情况下的默认输入值(当前是ClOR,注意l是小写的L,而不是大写的i),点击“登录并申请”按钮后,会看到登录框: 选择“验证码登录”,输入手机号验证码后点击“确认登录”按钮,回到上一步的界面,但注意此时底部按钮显示的文字已变为“立即申请试用”: 点击上述按钮后完成试用申请,注意此时有可能出现验证码超时或者其他的错误信息,根据提示重新填写再点击按钮即可。申请成功后会自动弹出开始下载[make.bat]文件(该文件中即包含了申请的试用账号和密码),以及[RQDATA使用说明.pdf]。 使用VS Code打开make.bat文件: 记住其中的name(用户名)以及password(密码),注意密码是一串长达344个字符的密钥,上图中仅截取了很短一部分(别想偷懒,哈哈)。 然后运行VN Station,点击VN Trader Pro,在右侧的上层应用中加载CtaBacktester(CTA回测模块)后启动,在主界面顶部的菜单栏,找到“配置”按钮: 点击后打开VN Trader的全局配置对话框: 将之前已经准备好的RQData用户名和密码,分别填入到rqdata.username和rqdata.password两个字段中,然后点击“确定”按钮,弹出提示重启的对话框。 此时即可关闭VN Trader并重启,点击菜单栏“功能”->“CTA回测”,启动接下来我们要用到的CTA策略回测图形界面: 如果上一步的RQData账号密码配置正确,此时可以在中间底部的日志输出框中看到“RQData数据接口初始化成功”的信息。如果没有就说明配置有问题,回去重来吧。 窗口左上方的一系列编辑框和下拉框,用来控制和管理我们的回测功能。在本地代码编辑框中输入IF88.CFFEX,K线周期选择1m(即1分钟K线),然后选择要下载数据的开始日期和结束日期,点击“下载数据”按钮。 此时CtaBacktester模块就会自动从RQData服务器下载历史数据,并完成数据结构转化后插入到VN Trader的数据库中(默认使用SQLite,数据文件位于.vntrader目录下的database.db),下载完成后同样会在日志输出框中看到相应信息: 运行历史回测 有了历史数据后,我们就可以开始跑历史回测。在左上角的交易策略下拉框里,应该已经能找到上一篇教程我们编写的DemoStrategy,选中后开始配置回测参数。 注意这里我们使用的是中金所股指期货的IF合约,回测时的参数要设置为股指期货所对应的属性。手续费率编辑框中输入0.000025(万0.25),交易滑点输入0.2(即单边成交1跳的滑点成本),合约乘数为300(300元每点),价格跳动也是0.2(股指期货最小价格变动),回测资金我们使用100万。 点击“开始回测”按钮,弹出参数配置对话框: 这里显示的fast_window和slow_window就是之前我们添加到parameters列表中的参数名称,这里我们直接使用默认数值,点击“确定”按钮后,我们的回测引擎就会自动开始执行策略回测的整个流程:加载数据、数据回放、模拟撮合、计算每日盈亏、统计指标、以及最后画出图表: 不出之前的意料,双均线策略的效果差的一塌糊涂,右侧图表的4个子图中: 子图1:资金变化曲线,笔直向下说明稳定亏损 子图2:最大回撤曲线,越来越大说明策略亏损越来越多 子图3:每日盈亏统计,红绿分布平均,但绿色密度更大(亏损) 子图4:盈亏的概率分布图,尖峰在0轴左侧(中位数日期发生亏损) 然后在中间顶部的表格中,可以看到回测相关的一些统计数据: 这策略干了什么事情能亏这么多钱呢,总有很多人会抱着不信邪的态度,此时点击左侧的“成交记录”按钮,可以看到回测过程中的每一笔成交记录: 还不信邪,可以点击“委托记录”按钮查看这些成交具体是由哪些委托触发的: 可以通过“成交记录”中的每条成交对应的委托号,在“委托记录”中找到策略下出的委托。细心的人可能已经发现上面两张图中,某一笔委托的价格和其对应成交的价格并不一致,这是因为我们在策略下单时使用了超价5元(为了保证成交),而回测仿真撮合时则是取了T+1时刻的最优成交价(也是实盘中最可能拿到的价格)。 在“每日盈亏”窗口中,可以看到以逐日盯市规则(期货结算规则),将每日的持仓和成交映射到当日收盘价后的当日整体盈亏情况: 最后,如果还是觉得死活不相信双均线策略怎么可能这么差,点击“K线图表按钮”,可以看到整个回测数据对应的K线图表: 上图中的黄色向上箭头代表多头成交(buy/cover),蓝色向下箭头则代表了空头成交(sell/short),可以通过键盘和鼠标拖动和缩放图表,看到自己想要的部分。 到了这里,是不是已经有点相信了“双均线策略就是垃圾”的说法?实际上从公平角度讲,以上看到的回测信息,并不能充分证明双均线信号的无效性,如果我们: 将手续费和滑点都调为0,这样不考虑交易成本影响 然后在回测时缩小fast_window到3,增大slow_window到80,即让长周期均线变得更加平稳 出来的结果则变成了: 从这张图上看,在不考虑交易成本时,双均线的来回穿插作为一种信号,可能还是有一定的预测效果(尽管也好不到哪里去)。 策略参数优化 实盘用可能是没希望了,但不妨碍我们想来折腾一下,看看在股指1分钟数据上到底怎样的均线组合能起到最好的效果,毕竟之前的3和80两个参数纯粹只是拍脑袋的结果。 假设我们想要看看fast_window,从2到20(步进2),slow_window,从20到100(步进10),参数分别两两组合出来的回测效果,看看能不能找到更好的均线组合。 比较傻的方法就是人工操作,每次将两个参数输入到回测的参数对话框里,然后运行等结果,再把结果记录在Excel表格里最后用来做排序比较。但对于这种机械重复的劳动,电脑比起人的效率要高得多得多,在本质上我们就是分别遍历两个参数的各种可能排列组合,然后针对每组组合,跑完回测并记录其中的关键结果,也就是所谓的“参数优化”。 CtaBacktester模块已经内置了策略参数优化的功能,点击左侧下方的“参数优化”按钮: 在弹出的对话框中,我们把之前的参数想法输入进去: 目标函数就选择最简单的总收益率 fast_window,开始数值为2,结束数值为20,每次步进为2(即2、4、6、8、10...) slow_window,开始数值为20,结束数值为100,每次步进为10(即20、30、40、50、60...) 点击“多进程优化”,使用暴力穷举算法(Brute-Force Algorithm),同时运行多个并行的Python进程,充分利用CPU的核心数量来加快优化速度。 优化完成后,日志信息中会有相应的提示,同时左下角的“优化结果”按钮会亮起: 点击后看到每组参数组合,所对应的目标函数结果: 效果最好的是fast_window为18,slow_window为90,带入到策略回测中运行后: 参数优化大法好!!! 可能在前面铺垫了那么多的情况下(过度拟合风险、双均线信号普通、移除了滑点手续费),你不见得还会脑子里蹦出这么一句话,但不可否认参数优化后的效果提升非常明显。 在本篇教程的最后,希望提醒大家的是:尽管看起来一路点点鼠标就能搞出个漂亮的资金曲线了,但实际上量化策略回测和优化过程中充满了各种各样的地雷。 到目前为止我们所讲述的只是最最基础的操作方法,还远没有涉及到实践经验的内容,这块要么大家用自己的真金白银在交易中慢慢积累,另一个成本更低的选择当然就是关注我们后续的进阶教程了! 了解更多知识,请关注vn.py社区公众号。

优秀的个人博客,低调大师

快速了解Service Mesh微服务架构实现服务间gRPC通信

在前面的文章之中我们介绍了基于Kubernetes及Istio如何一步一步把Service Mesh微服务架构玩起来!在该文章中,我们演示了一个非常贴近实战的案例,这里回顾下该案例的结构,如下图所示: 该案例所演示的就是我们日常使用微服务架构开发时,服务间最普遍的通信场景。在Spring Cloud微服务体系中,服务间可以通过Fegin+Ribbon组合的方式,实现服务间负载均衡方式的Http接口调用;但在Service Mesh架构中,服务发现及负载均衡等治理逻辑已经由SideCar代理,如果还希望延续Spring Cloud场景下服务间接口调用的代码体验,一般可以通过改写Feign组件,去掉其中关于服务治理的逻辑,只保留简单的接口声明式调用逻辑来实现。 上述案例中“micro-api->micro-order”之间的服务通信调用,就是基于该方式实现的(可参考之前的文章)。但在微服务架构中除了采用Http协议通信外,对于某些对性能有着更高要求的系统来说,采用通信效率更高的RPC协议往往是更合适的选择! 在基于Spring Cloud框架的微服务体系中,服务之间也可以通过RPC协议通信,但由于服务治理的需要,也需要一套类似于Fegin+Ribbon组合的SDK支持。例如gRPC框架就有针对Spring Boot框架的“grpc-client-spring-boot-starter”依赖支持!该项目是一个 gRPC 的 Spring Boot 模块,可以在 Spring Boot 中内嵌一个 gRPC Server 对外提供服务,并支持 Spring Cloud 的服务发现、注册、链路跟踪等等。 那么在Service Mesh微服务体系下,服务间基于gRPC框架的通信应该怎么实现呢?接下来,我将以案例中"micro-order->micro-pay"之间的服务调用为例,演示在Service Mesh微服务架构下实现服务间的gRPC通信调用,并将案例中Http+gRPC服务间通信的完整场景串起来! gRPC概述 在演示Service Mesh微服务架构下的gRPC通信场景之前,我们先简单介绍下RPC协议及gRPC框架的基本知识。 RPC(Remote Procedure Call),又称远程过程调用,是一种通过掩藏底层网络通信复杂性,从而屏蔽远程和本地调用区别的通信方式。相比于Http协议,RPC协议属于一种自定义的TCP协议,从而在实现时避免了一些Http协议信息的臃肿问题,实现了更高效率的通信。 在主流实现RPC协议的框架中,比较著名的有Dubbo、Thrift及gRPC等。因为目前主流的容器发布平台Kubernetes,以及Service Mesh开源平台Istio都是通过gRPC协议来实现内部组件之间的交互,所以在Service Mesh微服务架构中,服务间通信采用gRPC协议,从某种角度上说会更具有原生优势。况且在此之前,gRPC框架已经在分布式、多语言服务场景中得到了大量应用,因此可以预测在Service Mesh微服务架构场景下,基于gRPC框架的微服务通信方式会逐步成为主流。 gRPC是Google发布的基于HTTP/2.0传输层协议承载的高性能开源软件框架,提供了支持多种编程语言的、对网络设备进行配置和纳管的方法。由于是开源框架,通信的双方可以进行二次开发,所以客户端和服务器端之间的通信会更加专注于业务层面的内容,减少了对由gRPC框架实现的底层通信的关注。 接下来的内容就具体演示在Service Mesh微服务架构下,实现微服务“micro-order->micro-pay”的gRPC通信调用! 构建gRPC服务端程序(micro-pay) 首先从gRPC服务端的角度,在微服务micro-pay项目中集成gRPC-Java,并实现一个gRPC服务端程序。具体如下: 1、构建Spring Boot基本工程(micro-pay/micro-pay-client) 使用Spring Boot框架构建基本的Maven工程,为了工程代码的复用,这里单独抽象一个micro-pay-client工程,并定义micro-pay微服务gRPC服务接口的protobuf文件(*/proto/paycore.proto),代码如下: syntax = "proto3"; package com.wudimanong.pay.client; option java_multiple_files = true; option java_package = "com.wudimanong.micro.pay.proto"; service PayService { //定义支付rpc方法 rpc doPay (PayRequest) returns (PayResponse); } message PayRequest { string orderId = 1; int32 amount=2; } message PayResponse { int32 status = 1; } 如上所示,创建了一个基于protobuf协议的支付接口定义文件,其中定义了支付服务PayService及其中的doPay支付rpc方法,并定义了其请求和返回参数对象,具体的语法遵循“proto3”协议。 为了能够正常编译和生成protobuf文件所定义服务接口的代码,需要在项目pom.xml文件中引入jar包依赖及Maven编译插件配置,代码如下: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> .... <dependencies> .... <!--gRPC通信类库(截止目前的最新版本)--> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-all</artifactId> <version>1.36.1</version> </dependency> </dependencies> <build> <!--引入gRpc框架proto文件编译生产插件--> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>1.6.2</version> </extension> </extensions> <plugins> <plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>0.6.1</version> <configuration> <protocArtifact>com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier}</protocArtifact> <pluginId>grpc-java</pluginId> <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.36.0:exe:${os.detected.classifier}</pluginArtifact> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>compile-custom</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project> 这是单独关于gRPC接口proto文件定义的工程,定义后编译工程,maven就会根据前面定义的paycore.proto文件生成gRPC服务端/客户端相关代码。 完成后,继续构建micro-pay微服务的spring boot工程代码,并在其pom.xml文件中引入上述gRPC协议文件定义的依赖,例如: <!--引入支付服务gRPC ProtoBuf定义依赖--> <dependency> <groupId>com.wudimanong</groupId> <artifactId>micro-pay-client</artifactId> <version>1.0-SNAPSHOT</version> </dependency> 在micro-pay-client工程中所引入的gRPC相关的依赖及插件配置会自动继承至micro-pay工程! 2、编写gRPC支付服务代码 在micro-pay代码工程中创建一个PayCoreProvider接口代码,用于表示支付gRPC服务的入口(类似于Controller),其代码如下: package com.wudimanong.micro.pay.provider; import com.wudimanong.micro.pay.proto.PayRequest; import com.wudimanong.micro.pay.proto.PayResponse; import com.wudimanong.micro.pay.proto.PayServiceGrpc; import io.grpc.stub.StreamObserver; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Slf4j @Component public class PayCoreProvider extends PayServiceGrpc.PayServiceImplBase { /** * 实现ProtoBuf中定义的服务方法 * * @param request * @param responseStreamObserver */ @Override public void doPay(PayRequest request, StreamObserver<PayResponse> responseStreamObserver) { //逻辑处理(简单模拟打印日志) log.info("处理gRPC支付处理请求,orderId->{};payAmount{}", request.getOrderId(), request.getAmount()); //构建返回对象(构建处理状态) PayResponse response = PayResponse.newBuilder().setStatus(2).build(); //设置数据响应 responseStreamObserver.onNext(response); responseStreamObserver.onCompleted(); } } 上述代码所引入的一些依赖代码如PayServiceGrpc等,就是前面定义paycore.proto文件所生成的桩文件代码!由于只是简单测试,这里仅仅打印了下日志就返回了,如果涉及复杂业务还是可以按照MVC分层架构思想进行代码拆分! 3、编写gRPC与Spring Boot框架集成配置代码 在Spring Cloud微服务中集成gRPC可以通过前面提到的“grpc-client-spring-boot-starter”来实现,但目前还没有现成的支持Service Mesh架构下的集成SDK,所以这里通过手工配置定义的方式实现集成。先创建一个配置类,代码如下: package com.wudimanong.micro.pay.config; import com.wudimanong.micro.pay.provider.PayCoreProvider; import io.grpc.Server; import io.grpc.ServerBuilder; import java.io.IOException; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Slf4j @Component public class GrpcServerConfiguration { @Autowired PayCoreProvider service; /** * 注入配置文件中的端口信息 */ @Value("${grpc.server-port}") private int port; private Server server; public void start() throws IOException { // 构建服务端 log.info("Starting gRPC on port {}.", port); server = ServerBuilder.forPort(port).addService(service).build().start(); log.info("gRPC server started, listening on {}.", port); // 添加服务端关闭的逻辑 Runtime.getRuntime().addShutdownHook(new Thread(() -> { log.info("Shutting down gRPC server."); GrpcServerConfiguration.this.stop(); log.info("gRPC server shut down successfully."); })); } private void stop() { if (server != null) { // 关闭服务端 server.shutdown(); } } public void block() throws InterruptedException { if (server != null) { // 服务端启动后直到应用关闭都处于阻塞状态,方便接收请求 server.awaitTermination(); } } } 如上所示,在该配置代码中,通过gRPC-Java依赖所提供的Server对象构建了gRPC服务端启动、停止、阻塞的方法,并在启动时将前面定义的服务端类通过“.addService()”方法进行了加入(可考虑封装更优雅的方式)! 为了让该配置类与Spring Boot集成,再定义一个集成类,代码如下: package com.wudimanong.micro.pay.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; @Component public class GrpcCommandLineRunner implements CommandLineRunner { @Autowired GrpcServerConfiguration configuration; @Override public void run(String... args) throws Exception { configuration.start(); configuration.block(); } } 上述代码会在Spring Boot应用启动时自动加载,其中的逻辑就是启动gRPC服务,并阻塞等待连接! 接下来在配置文件中定义服务所开启的gRPC端口,配置如下: spring: application: name: micro-pay server: port: 9092 #定义gRPC服务开放的端口 grpc: server-port: 18888 该配置所定义的参数在前面的服务配置类中引用,表示gRPC服务开启的端口,这里定义的是18888! 到这里gRPC服务端工程代码就构建完成了,从整体上看就是Spring Boot+gRPC的集成与整合,这其中没有引入Spring Boot定制的gRPC集成SDK,目的在于避免其中所涉及的客户端服务治理逻辑(与前面Http调用不直接引入Open Feign一样)。 构建gRPC客户端程序(micro-order) 接下来我们改造micro-order微服务,使其成为调用micro-pay微服务的gRPC客户端程序! 1、引入gRPC客户端依赖包 引入前面定义micro-pay gRPC服务时构建的micro-pay-client protobuf工程依赖,代码如下: <!--引入支付服务gRPC ProtoBuf定义依赖--> <dependency> <groupId>com.wudimanong</groupId> <artifactId>micro-pay-client</artifactId> <version>1.0-SNAPSHOT</version> </dependency> 2、业务逻辑中实现gRPC服务调用 接下来在micro-order逻辑中调用gRPC支付服务,代码示例如下: @Slf4j @Service public class OrderServiceImpl implements OrderService { /** * 引入gRPC客户端配置依赖 */ @Autowired GrpcClientConfiguration gRpcClent; @Override public CreateOrderBO create(CreateOrderDTO createOrderDTO) { log.info("现在开始处理下单请求....."); //生成订单号 String orderId = String.valueOf(new Random(100).nextInt(100000) + System.currentTimeMillis()); //构建支付请求(gRPC调用) PayRequest payRequest = PayRequest.newBuilder().setOrderId(orderId).setAmount(createOrderDTO.getAmount()) .build(); //使用stub发送请求到服务端 PayResponse payResponse = gRpcClent.getStub().doPay(payRequest); log.info("pay gRpc response->" + payResponse.toString()); return CreateOrderBO.builder().orderId(orderId).status(payResponse.getStatus()).build(); } } 如上所示,该业务逻辑在接收micro-api通过Http调用的请求后,会在逻辑实现过程中通过gRPC协议访问支付服务,其中涉及的接口定义代码,由protobuf文件所定义! 3、gRPC客户端配置 上述逻辑是通过定义“GrpcClientConfiguration”gRPC客户端配置类来实现gRPC服务调用的,该配置类代码如下: @Slf4j @Component public class GrpcClientConfiguration { /** * 支付gRPC Server的地址 */ @Value("${server-host}") private String host; /** * 支付gRPC Server的端口 */ @Value("${server-port}") private int port; private ManagedChannel channel; /** * 支付服务stub对象 */ private PayServiceGrpc.PayServiceBlockingStub stub; public void start() { //开启channel channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext().build(); //通过channel获取到服务端的stub stub = PayServiceGrpc.newBlockingStub(channel); log.info("gRPC client started, server address: {}:{}", host, port); } public void shutdown() throws InterruptedException { //调用shutdown方法后等待1秒关闭channel channel.shutdown().awaitTermination(1, TimeUnit.SECONDS); log.info("gRPC client shut down successfully."); } public PayServiceGrpc.PayServiceBlockingStub getStub() { return this.stub; } } 如上所示配置代码,通过依服务配置文件指定的gRPC服务端地址+端口,实现对gRPC客户端的配置,其中主要包括启动和停止方法,并在启动的过程中初始化gRPC服务客户端的桩代码的实例(可考虑更优雅地实现)。 在该配置类中所依赖的gRPC服务端地址+端口配置,依赖于服务配置文件的定义,代码如下: spring: application: name: micro-order server: port: 9091 #支付微服务Grpc服务地址、端口配置 server-host: ${grpc_server_host} server-port: ${grpc_server_port} 如果是本地测试可以直接指定grpc_server_host及端口的值,但在Service Mesh微服务架构中,直接在应用的配置文件中指定其他微服务的地址及端口可能并不是很灵活,这个配置信息将在发布Kubernetes集群时,通过Kubernetes发布文件注入! 为了让gRPC客户端配置与Spring Boot集成,这里也需要定义一个Spring Boot加载类,代码如下: @Component @Slf4j public class GrpcClientCommandLineRunner implements CommandLineRunner { @Autowired GrpcClientConfiguration configuration; @Override public void run(String... args) throws Exception { //开启gRPC客户端 configuration.start(); //添加客户端关闭的逻辑 Runtime.getRuntime().addShutdownHook(new Thread(() -> { try { configuration.shutdown(); } catch (InterruptedException e) { e.printStackTrace(); } })); } } 该代码将在Spring Boot应用自动时自动加载!到这里micro-order gRPC客户端配置就完成了! 将部署服务至Service Mesh架构环境 前面基于“micro-order->micro-pay”微服务间的gRPC调用场景,分别将两个微服务改造成了gRPC服务端/客户端。但此时从代码上是很难看出来它们二者之间应该怎么实现调用!而这也恰恰就印证了Service Mesh架构的优势,服务的发现、及负载均衡调用之类的服务治理逻辑,已经完全不用微服务自己管了! 在Istio中,它们是基于Kubernetes的Service发现机制+Istio-proxy(SideCar代理)来实现的。而具体的操作就是通过微服务Kubernetes服务发布文件的定义,接下来分别定义micro-order及micro-pay的Kubernetes发布文件。 先看下作为gRPC服务端的micro-pay的发布文件(micro-pay.yaml),代码如下: apiVersion: v1 kind: Service metadata: name: micro-pay labels: app: micro-pay service: micro-pay spec: type: ClusterIP ports: - name: http #容器暴露端口 port: 19092 #目标应用端口 targetPort: 9092 #设置gRPC端口 - name: grpc port: 18888 targetPort: 18888 selector: app: micro-pay --- apiVersion: apps/v1 kind: Deployment metadata: name: micro-pay-v1 labels: app: micro-pay version: v1 spec: replicas: 2 selector: matchLabels: app: micro-pay version: v1 template: metadata: labels: app: micro-pay version: v1 spec: containers: - name: micro-pay image: 10.211.55.2:8080/micro-service/micro-pay:1.0-SNAPSHOT imagePullPolicy: Always tty: true ports: - name: http protocol: TCP containerPort: 19092 #指定服务gRPC端口 - name: grpc protocol: TCP containerPort: 18888 如上所示k8s发布文件,主要是定义了Service服务访问资源及Deployment容器编排资源,这两种资源都是Kubernetes的资源类型,在容器编排资源和服务资源中分别定义了gRPC的访问端口,通过这种设置,后续gRPC客户端通过Service资源访问服务时,就能够进行端口映射了! 而其他配置则是基本的Kubernetes发布部署逻辑,其中涉及的镜像,需要在发布之前,通过构建的方式对项目进行Docker镜像打包并上传私有镜像仓库(如果有疑问,可以参考本号之前的文章)。 接下来继续看看作为gRPC客户端的micro-order微服务的k8s发布文件(micro-order.yaml),代码如下: apiVersion: v1 kind: Service metadata: name: micro-order labels: app: micro-order service: micro-order spec: type: ClusterIP ports: - name: http #此处设置80端口的原因在于改造的Mock FeignClient代码默认是基于80端口进行服务调用 port: 80 targetPort: 9091 selector: app: micro-order --- apiVersion: apps/v1 kind: Deployment metadata: name: micro-order-v1 labels: app: micro-order version: v1 spec: replicas: 2 selector: matchLabels: app: micro-order version: v1 template: metadata: labels: app: micro-order version: v1 spec: containers: - name: micro-order image: 10.211.55.2:8080/micro-service/micro-order:1.0-SNAPSHOT imagePullPolicy: Always tty: true ports: - name: http protocol: TCP containerPort: 19091 #环境参数设置(设置微服务返回gRPC服务端的地址+端口) env: - name: GRPC_SERVER_HOST value: micro-pay - name: GRPC_SERVER_PORT value: "18888" 在该发布文件中,需要说明的主要就是通过容器env环境参数的设置,指定了之前gRPC客户端服务配置中所依赖的参数变量“GRPC_SERVER_HOST及GRPC_SERVER_PORT”,其中服务地址就是micro-pay微服务在Kubernetes中Service资源定义的名称,端口则是gRPC服务端所开启的端口。 这样在gRPC客户端在Kubernetes集群中根据Service名称发起微服务调用时,Kubernetes集群自身的服务发现逻辑就能自动将请求映射到相应的Pod资源了!这其实就是Service Mesh微服务架构服务发现的基本逻辑! 接下来将微服务进行发布,这里假设你已经部署了一套Kubernetes集群并安装了基于Istio的Service Mesh微服务架构环境,最终的部署效果如下所示: root@kubernetes:/opt/istio/istio-1.8.4# kubectl get pods NAME READY STATUS RESTARTS AGE micro-api-6455654996-9lsxr 2/2 Running 2 43m micro-order-v1-744d469d84-rnqq8 2/2 Running 0 6m28s micro-order-v1-744d469d84-vsn5m 2/2 Running 0 6m28s micro-pay-v1-7fd5dd4768-txq9d 2/2 Running 0 43s micro-pay-v1-7fd5dd4768-wqw6b 2/2 Running 0 43s 如上所示,可以看到案例所涉及的微服务都被部署了,并且对应的SideCar代理(istio-proxy)也被正常启动了!为了演示负载均衡效果,这里micro-order及micro-pay都分别被部署了两个副本! 微服务多副本负载均衡调用演示 如果环境都没啥问题,此时可以通过调用Istio Gateway来访问micro-api服务,然后micro-api服务会通过Http的方式访问micro-order服务,之后micro-order服务通过gRPC协议调用micro-pay服务。 通过curl命令访问Istio Gateway网关服务,效果如下: curl -H "Content-Type:application/json" -H "Data_Type:msg" -X POST --data '{"businessId": "202012102", "amount": 100, "channel": 2}' http://10.211.55.12:30844/api/order/create 如果正常返回响应结果,则说明上述调用链路走通了!此时分别通过观察服务的业务日志和istio-proxy代理日志来加以观测! 其中micro-pay两个实例(PodA~PodB)业务日志信息: //支付微服务接口访问日志(POD-A) root@kubernetes:~# kubectl logs micro-pay-v1-7fd5dd4768-txq9d micro-pay .... 2021-04-01 14:46:15.818 INFO 1 --- [ main] c.w.m.p.config.GrpcServerConfiguration : Starting gRPC on port 18888. 2021-04-01 14:46:18.859 INFO 1 --- [ main] c.w.m.p.config.GrpcServerConfiguration : gRPC server started, listening on 18888. 2021-04-01 15:07:36.709 INFO 1 --- [ault-executor-0] c.w.micro.pay.provider.PayCoreProvider : 处理gRPC支付处理请求,orderId->1617289656289;payAmount100 //支付微服务接口访问日志(POD-B) root@kubernetes:~# kubectl logs micro-pay-v1-7fd5dd4768-wqw6b micro-pay ... 2021-04-01 15:34:59.673 INFO 1 --- [ main] c.w.m.p.config.GrpcServerConfiguration : Starting gRPC on port 18888. 2021-04-01 15:35:06.175 INFO 1 --- [ main] c.w.m.p.config.GrpcServerConfiguration : gRPC server started, listening on 18888. 2021-04-01 15:40:22.019 INFO 1 --- [ault-executor-0] c.w.micro.pay.provider.PayCoreProvider : 处理gRPC支付处理请求,orderId->1617291624127;payAmount100 2021-04-01 15:44:31.630 INFO 1 --- [ault-executor-2] c.w.micro.pay.provider.PayCoreProvider : 处理gRPC支付处理请求,orderId->1617291867537;payAmount100 可以看到,多次访问接口,基于gRPC的微服务调用也实现了负载均衡调用!接下来分别看下这两个微服务的istio-proxy(SideCar代理)的日志,具体如下: --istio-proxy代理日志(POD-A) root@kubernetes:~# kubectl logs micro-pay-v1-7fd5dd4768-txq9d istio-proxy ... 2021-04-01T15:34:48.009972Z info Envoy proxy is ready [2021-04-01T15:40:26.240Z] "POST /com.wudimanong.pay.client.PayService/doPay HTTP/2" 200 - "-" 22 7 498 477 "-" "grpc-java-netty/1.36.1" "8eb318e5-ac09-922d-9ca7-603a5c14bdd5" "micro-pay:18888" "127.0.0.1:18888" inbound|18888|| 127.0.0.1:57506 10.32.0.10:18888 10.32.0.12:36844 outbound_.18888_._.micro-pay.default.svc.cluster.local default 2021-04-01T15:45:18.377555Z info xdsproxy disconnected ... [2021-04-01T15:45:34.885Z] "POST /com.wudimanong.pay.client.PayService/doPay HTTP/2" 200 - "-" 22 7 1200 171 "-" "grpc-java-netty/1.36.1" "c08d540e-db46-9228-b381-0808ac08377e" "micro-pay:18888" "127.0.0.1:18888" inbound|18888|| 127.0.0.1:33218 10.32.0.10:18888 10.32.0.2:42646 outbound_.18888_._.micro-pay.default.svc.cluster.local default ... 2021-04-01T15:52:49.825955Z info xdsproxy connecting to upstream XDS server: istiod.istio-system.svc:15012 如上所示,可以看到istio-proxy代理日志中显示了通过post方式转发gRPC服务的情况,而且可以看出gRRPC是采用Http/2实现的! 后记 本文通过实战案例,演示了在Service Mesh微服务架构下,服务间通过gRPC协议实现通信调用的场景! 欢迎大家关注我的公众号【风平浪静如码】,海量Java相关文章,学习资料都会在里面更新,整理的资料也会放在里面。 觉得写的还不错的就点个赞,加个关注呗!点关注,不迷路,持续更新!!!

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册