实时即未来?一个小微企业心中的流计算

摘要:本文由墨芷技术团队唐铎老师分享,主要讲述其技术团队内部引入流计算的整个过程,包括最初的决策、期间的取舍以及最终落地,一路走来他们的思考、感悟以及经验分享。

  1. 初识 Flink
  2. 为什么一定要上 Flink
  3. 一个小例子
  4. 总结

Tips:“实时即未来”在很多人的眼中可能只是一句口号,但在墨芷,这是他们亲手创造的故事。

大家好,我们是浙江墨芷信息科技有限公司,一个刚刚满3年的创业团队,主营业务是电商代运营,目前是淘宝四星级服务商。

我们的核心团队先后服务于国内知名女装、家电、母婴、男装、童装、珠宝饰品、化妆品等多个品类知名品牌商,具有丰富的品牌运营管理经验,服务过的品牌均在行业前列。

主营业务围绕泛时尚领域(服装、婴童、美妆、生活家居、珠宝饰品)互联网平台品牌运营及全网品牌推广,涉及品牌定位与推广、电商运营、商品企划与经营、视觉设计、营销推广、顾客服务、仓储物流等综合端到端服务。

本文将分享墨芷与流计算结缘的故事。

01 初识Flink

第一次接触 Flink 流计算是在18年9月的云栖大会上,大沙老师与在场以及线上的开发者们分享 Flink,会场座无虚席,会场门外还围着三五层的听众。虽然老师的讲解时间不长,听的也是一知半解,却有种很强烈感觉,“实时,即是未来”。

从云栖小镇回来后,跟自己的团队讨论了一下,大家决定向 Flink 开进,但前进的难度是我们没有预料到的。那个时候学习资料很少,一本《Flink 基础教程》被我们翻来复去的看,动手实操门槛较高,进度非常不理想。

640 1.png
图1 云栖大会流计算分会场

19年3月,有幸参加了在杭州举行的 Flink 用户交流会,报名时只是抱着学习的心态去旁听,但到现场后震惊了,参会的不仅是 Flink 的深度用户,更甚的是每位都来自估值百亿以上的大厂。无论是讨论的内容还是出身都让我们感到自卑。

回来之后的第二天,一起去的五个人不约而同的都到公司加班,即便不说透,这次会议给大家带来的心丽冲击是巨大的,也促使了我们下定决心,即便难度再大也要把 Flink 应用起来。

在此一个月之后,我们用 Java 编写的 Flink Job 上线了,即便实现的功能很简单,但这是我们坚实的一小步。

640 2.png
图2 社区里广为流传的一张照片

2020年年初,疫情肆虐,团队人员变动,客观条件使我们不得不放弃之前用 Java 编写的一切,转投 Python。这个决定极其艰难,我们很清楚,一切将回到原点。

但我们与 Flink 的缘分还没结束。刚好,我们看到社区发起了 PyFlink 扶持计划,于是邮件咨询,也有幸被眷顾。接下来的一个月时间,我们在金竹、付典、断尘几位老师的帮助下,将原有的 Flink Job 迁移到了 PyFlink 上,同时也带着需求去学习 PyFlink 的特性。这才有了与大家分享学习成果的机会。

02 为什么一定要上Flink

说到这,一定有同行问,为啥一个小微企业还要上流计算,用得上吗?

我们面临的是若干个严峻的事实:

  1. 人员数量的膨胀带来了成倍的开销。公司用了3年时间,将团队规模扩张到的150人,在嘉兴这个小城市里这是很不容易的一件事,而且主业是电商代运营,这种工作更像我们软件行业的项目外包。一提到外包,同行们肯定会联想到人力配备,简单讲,有项目做才能养活人,没项目的话,闲置的人力成本就是亏本买卖。
  2. 人效提升困难,规定再严格的 KPI 也会有瓶颈。同事们每天上班第一件事就是发前一天的销售业绩,只是这个小小的日报,就要耗费半个小时的时间,数据的时效又是“T + 1”,略显滞后。
  3. 在做直通车推广时,由于同事的疏忽,一些已经不再需要付费推广或可以降低竞价的商品还在按照原计划持续烧钱,人工监控很难及时地发现这些问题

作为 IT 规划的主导者,一直以来我都希望可以依托团队在电商经营上丰厚的经验及操盘能力,这样目标很明了,就是搭建我们自己的数据实时决策平台。

决策,我们暂且拆开来看,决断与策略。团队自有经验及做事的判断逻辑,我们把它划到策略一侧,现在我们缺少的是“决断的能力”,决断既要考虑准确性,又要顾及时效性,当然,如果决断时能渐进地优化策略也是极好的。所以我们大致规划了图3中的架构。从下至上依次为我们的 DataSource(数据源),Swarm(多源数据收集平台),DW(数据仓库),NB(电商离线数据中台),Radical(电商数据决策平台)。数据逐层向上被收集,保存,计算,展现,应用,而Flink在数据的生命周期内担当实时计算的重要任务。

还记得电商场景下商家被薅羊毛的新闻吗?

目前没有任何一款电商 ERP 有针对这方面的功能设计。如果可以编写一个基于 Flink 流计算的实时监控异常销售情况的小插件,在获取到订单中的实付金额去比对之前的商品价格,再结合最新的库存计算后判断得出结果,适时弹出告警,那样的悲剧是否可以避免?

当然,对于电商场景下实时计算的应用点可以开的脑洞是没有边界的,况且,如果以上的系统通过不断地迭代和优化,是否会代替人工成本呢?如果做到了,那一定是一个新的开端。

项目来项目走,短短三年,我们这个小微企业没有记录多大的数据量,无非就是店铺的运营和订单数据,数据采集平台帮助我们秒级地监控在运营的15家店铺,每个店铺有60多个数据监控点。但只有依托 Flink 的流计算,我们才能尽早地从查看到我们想要的数据结果并且做出正确的决策,今天给大家分享的例子也是在这个背景上的。

640 3.png
图3 架构图与技术栈(数据流向)

03 一个小例子

根据我们自身的需求以及 Flink 的特性,我们搭建了一个基于 Flink 流计算的实时监控系统,以监测异常情况。以下是一个线上商品价格实时监控的小例子,这是我们在参加 PyFlink 扶持计划这段时间里完成的,希望可以让大家感受到 PyFlink 开发的便捷。

项目背景

公司里有一个美妆经销项目,即存在旗舰店的同时有数以千计的经销商店铺,业务同事希望可以通过技术手段监控经销商店铺的商品价格不低于旗舰店,避免影响旗舰店销售,于是我们想到如下思路:

640 4.png
图4 问题解决思路

实践过程

根据以上思路,我们先采集到了如下数据样例:

{"shop_name": "经销商1","item_name": "凝时精华","item_url": "https://*****","item_img": "https://*****","item_price": 200.00,"discount_info": "['每满200减20,上不封顶']","item_size": ""},{"shop_name": "经销商2","item_name": "精华油1","item_url": "https://*****","item_img": "https://","item_price": 200.00,"discount_info": "['每满200减15,上不封顶']","item_size": "125ml"}

然后,根据数据样例可以编写注册 Kafka source 的方法。

# register kafka_source
def register_rides_source_from_kafka(st_env):st_env \.connect(  # declare the external system to connect toKafka().version("universal").topic("cbj4")# .topic("user").start_from_earliest().property("zookeeper.connect", "localhost:2181").property("bootstrap.servers", "localhost:9092")) \.with_format(  # declare a format for this systemJson().fail_on_missing_field(True).schema(DataTypes.ROW([DataTypes.FIELD('shop_name', DataTypes.STRING()),DataTypes.FIELD('item_name', DataTypes.STRING()),DataTypes.FIELD('item_url', DataTypes.STRING()),DataTypes.FIELD('item_img', DataTypes.STRING()),DataTypes.FIELD('item_price', DataTypes.STRING()),DataTypes.FIELD('discount_info', DataTypes.STRING()),DataTypes.FIELD('item_size', DataTypes.STRING()),]))) \.with_schema(  # declare the schema of the tableSchema().field("shop_name", DataTypes.STRING()).field("item_name", DataTypes.STRING()).field("item_url", DataTypes.STRING()).field("item_img", DataTypes.STRING()).field("item_price", DataTypes.STRING()).field('discount_info', DataTypes.STRING()).field("item_size", DataTypes.STRING())) \.in_append_mode() \.register_table_source("KafkaSource")

商品价格参考的 CSV 文件的数据样例为:

1,精华油1,125ml,**,************,敏感肌可用的全身精华油,****,200,180
2,精华油1,200ml,**,************,提亮美白、淡化疤痕,****,300,280
3,按摩油1,125ml,**,************,有效增加肌肤弹性,****,200,180
4,按摩油1,200ml,**,************,持续柔润滋养肌肤,****,300,280
5,按摩油2,125ml,**,************,润弹紧致,深层滋润肌肤,****,300,280
6,沐浴露,500ml,**,************,舒缓镇静,滋润干燥的皮肤,防止肌肤干燥,****,100,80
7,凝时精华,4x6ml,**,************,密集淡纹 多效抗氧 紧致弹润,****,200,180
8,精华油2,30ml,**,************,改善脆弱敏感干皮。小分子精华渗透肌底,密集补水,****,200,180
9,洁面凝胶,200ml,**,************,痘肌洁面优选,****,100,80

于是我们可以编写注册 CSV source 的方法。

# register csv_source
def register_rides_source_from_csv(st_env):# 数据源文件source_file = '/demo_job1/控价表.csv'# 创建数据源表st_env.connect(FileSystem().path(source_file)) \.with_format(OldCsv().field_delimiter(',').field('xh', DataTypes.STRING())  # 序号.field('spmc', DataTypes.STRING())  # 商品名称.field('rl', DataTypes.STRING())  # 容量.field('xg', DataTypes.STRING())  # 箱规.field('txm', DataTypes.STRING())  # 条形码.field('gx', DataTypes.STRING())  # 功效.field('myfs', DataTypes.STRING())  # 贸易方式.field('ztxsjg', DataTypes.STRING())  # 主图显示价格.field('dpzddsj', DataTypes.STRING())  # 单瓶最低到手价) \.with_schema(Schema().field('xh', DataTypes.STRING())  # 序号.field('spmc', DataTypes.STRING())  # 商品名称.field('rl', DataTypes.STRING())  # 容量.field('xg', DataTypes.STRING())  # 箱规.field('txm', DataTypes.STRING())  # 条形码.field('gx', DataTypes.STRING())  # 功效.field('myfs', DataTypes.STRING())  # 贸易方式.field('ztxsjg', DataTypes.STRING())  # 主图显示价格.field('dpzddsj', DataTypes.STRING())  # 单瓶最低到手价) \.register_table_source('CsvSource')

以及,我们想要输出到 CSV 的样式:

经销商1,按摩油1,https://**********,https://**********,200.00,[],125ml,200.0,3,按摩油1,125ml,**,************,敏感肌可用的全身精华油,****,200,180
经销商2,精华油2,https://**********,https://**********,190.00,[],30ml,190.0,8,精华油2,30ml,**,************,改善脆弱敏感干皮。小分子精华渗透肌底,密集补水,****,200,180
经销商3,精华油2,https://**********,https://**********,200.00,[],30ml,200.0,8,精华油2,30ml,**,************,改善脆弱敏感干皮。小分子精华渗透肌底,密集补水,****,200,180
经销商1,精华油2,https://**********,https://**********,200.00,['每满200减20;上不封顶'],30ml,180,8,精华油2,30ml,**,************,改善脆弱敏感干皮。小分子精华渗透肌底,密集补水,****,200,180
经销商1,按摩油1,https://**********,https://**********,200.00,['每满200减20;上不封顶'],125ml,180,3,按摩油1,125ml,**,************,有效增加肌肤弹性,****,200,180
经销商3,按摩油1,https://**********,https://**********,200.00,['每满200减20;上不封顶'],125ml,180.0,3,按摩油1,125ml,**,************,有效增加肌肤弹性,****,200,180
经销商2,精华油1,https://**********,https://**********,200.00,['每满200减20;上不封顶'],125ml,180.0,1,精华油1,125ml,**,************,敏感肌可用的全身精华油,****,200,180
经销商3,精华油1,https://**********,https://**********,200.00,['每满200减20;上不封顶'],125ml,180.0,1,精华油1,125ml,**,************,敏感肌可用的全身精华油,****,200,180
经销商1,精华油1,https://**********,https://**********,300.00,['每满200减20;上不封顶'],200ml,280.0,2,精华油1,200ml,**,************,提亮美白、淡化疤痕,****,300,280
经销商1,精华油1,https://**********,https://**********,190.00,['每满200减20;上不封顶'],125ml,190.0,1,精华油1,125ml,**,************,敏感肌可用的全身精华油,****,200,180

根据输出样式,我们来编写注册 CSV sink 的方法。

# register csv sink
def register_sink(st_env):result_file = "./result.csv"sink_field = {"shop_name": DataTypes.STRING(),"item_name": DataTypes.STRING(),"item_url": DataTypes.STRING(),"item_img": DataTypes.STRING(),"item_price": DataTypes.STRING(),"discount_info": DataTypes.STRING(),# "discount_info": DataTypes.ARRAY(DataTypes.STRING()),"item_size": DataTypes.STRING(),"min_price": DataTypes.FLOAT(),"xh": DataTypes.STRING(),"spmc": DataTypes.STRING(),"rl": DataTypes.STRING(),"xg": DataTypes.STRING(),"txm": DataTypes.STRING(),"gx": DataTypes.STRING(),"myfs": DataTypes.STRING(),"ztxsjg": DataTypes.STRING(),"dpzddsj": DataTypes.STRING(),}st_env.register_table_sink("result_tab",CsvTableSink(list(sink_field.keys()),list(sink_field.values()),result_file))

输入和输出都有了,我们根据业务同事要求的计算和判断逻辑,即销商店铺的商品价格不低于旗舰店这个规则去编写。

根据编写业务的逻辑,Table API 中算子不能满足所有需求,所以我们需要自定义 UDF 去处理其中几个字段,分别为“根据商品名称匹配实际商品”,“根据商品名称、商品页面价格,识别商品容量”,“按需计算优惠价格”,“格式化优惠券信息”等。

# -*- coding: utf-8 -*-import re
import loggingfrom pyflink.table import DataTypes
from pyflink.table.udf import udf, ScalarFunction# Extend ScalarFunction
class IdentifyGoods(ScalarFunction):""" 识别商品名称,与标准商品名称对应 """def eval(self, item_name):logging.info("进入 UDF")logging.info(item_name)# 标准商品名称regexes = re.compile(r'[精华油洁面凝胶沐浴露凝时精华12]')items = ["精华油1", "按摩油1", "按摩油1", "精华油2", "洁面凝胶", "沐浴露", "凝时精华"]items_set = []for index, value in enumerate(items):items_set.append(set(list(value)))  # 一个标题转成 set,方便做交集# 先匹配商品名称之外的字符,再去掉sub_str = re.sub(regexes, '', item_name)spbt = re.sub(repr([sub_str]), '', item_name)  # repr 强制变量非转义# 找到最为匹配的商品标题,否则认作未知商品intersection_len = 0items_index = Nonefor index, value in enumerate(items_set):j = value & set(list(spbt))  # 交集j_len = len(list(j))if j_len > intersection_len:intersection_len = j_lenitems_index = indexitem_name = '未知商品' if items_index is None else items[items_index]logging.info(item_name)return item_nameidentify_goods = udf(IdentifyGoods(), DataTypes.STRING(), DataTypes.STRING())class IdentifyCapacity(ScalarFunction):""" 根据商品名称、商品页面价格,识别商品容量 """def eval(self, item_name, price):# 初始化 商品价格与商品规格price = 0 if len(price) == 0 else float(price)item_size = ''# 此处,判断逻辑待修改重构,存在以外BUGif float(price) <= float(5):logging.info('这是优惠券!!!')elif item_name == "精华油1" and price > 200 and price <= 300:item_size = '200ml'elif item_name == "精华油1" and price <= 200:item_size = '125ml'elif item_name == "精华油1" and price >= 300:item_size = '精华油1组合装'elif item_name == "按摩油1" and price > 200 and price <= 300:item_size = '200ml'elif item_name == "按摩油1" and price <= 200:item_size = '125ml'elif item_name == "按摩油1" and price >= 300:item_size = '按摩油1组合装'elif item_name == "按摩油2":item_size = '125ml'elif item_name == "精华油2":item_size = '30ml'elif item_name == "洁面凝胶":item_size = '200ml'elif item_name == "沐浴露":item_size = '500ml'elif item_name == "凝时精华":item_size = '4x6ml'return item_sizeidentify_capacity = udf(IdentifyCapacity(), [DataTypes.STRING(), DataTypes.STRING()], DataTypes.STRING())# Named Function
@udf(input_types=[DataTypes.STRING(),DataTypes.STRING()],result_type=DataTypes.FLOAT())
def get_min_price(price, discount_info):""" 按需计算优惠价格 """price = 0 if len(price) == 0 else float(price)# 匹配所有优惠券coupons = []for i in eval(discount_info):regular_v1 = re.findall(r"满\d+减\d+", i)if len(regular_v1) != 0:coupons.append(regular_v1[0])regular_v2 = re.findall(r"每满\d+减\d+", i)if len(regular_v2) != 0:coupons.append(regular_v2[0])# 如果有优惠券信息,则计算最低价min_price = pricemayby_price = []if len(coupons) >= 0:regexes_v2 = re.compile(r'\d+')for i in coupons:a = re.findall(regexes_v2, i)cut_price = min(float(a[0]), float(a[1]))flag_price = max(float(a[0]), float(a[1]))if flag_price <= price:mayby_price.append(min_price - cut_price)if len(mayby_price) > 0:min_price = min(mayby_price)return min_price# Callable Function
class FormatDiscountInfo(object):""" 格式化优惠券信息,以便输出 .csv 文件使用 """def __call__(self, discount_str):discount_str = str(discount_str).replace(',', ";")return discount_strformat_discount_info = udf(f=FormatDiscountInfo(), input_types=DataTypes.STRING(), result_type=DataTypes.STRING())

最后编写计算 job 的主体方法:

# query
def calculate_func(st_env):# 坐标为采集数据表left = st_env.from_path("KafkaSource") \.select("shop_name, ""identify_goods(item_name) as item_name, "  # 识别商品名称与基础信息表对应"item_url, ""item_img, ""item_price, ""discount_info, ""item_size") \.select("shop_name, ""item_name, ""item_url, ""item_img, ""item_price, ""discount_info, ""identify_capacity(item_name, item_price) as item_size, "  # 根据商品名称与商品标价识别商品容量"get_min_price(item_price, discount_info) as min_price "  # 根据页面价与优惠信息计算最低价) \.select("shop_name, ""item_name, ""item_url, ""item_img, ""item_price, ""format_discount_info(discount_info) as discount_info, "  # 格式化优惠信息,方便存放到 .csv文件"item_size, ""min_price ")# 右表为基础信息表right = st_env.from_path("CsvSource") \.select("xh, spmc, rl, xg, txm, gx, myfs, ztxsjg, dpzddsj")result = left.join(right).where("item_name = spmc && item_size = rl")  # 按商品名称、商品容量 join 两表result.insert_into("result_tab")  # 输出 join 结果至 csv sink# main function
def get_price_demo():# init envenv = StreamExecutionEnvironment.get_execution_environment()env.set_parallelism(1)  # 设置并行度env.set_stream_time_characteristic(TimeCharacteristic.EventTime)
st_env = StreamTableEnvironment.create(
env,environment_settings=EnvironmentSettings.new_instance().use_blink_planner().build())# register sourceregister_rides_source_from_csv(st_env)register_rides_source_from_kafka(st_env)# register sinkregister_sink(st_env)# register functionst_env.register_function("identify_goods", identify_goods)st_env.register_function("identify_capacity", identify_capacity)st_env.register_function("get_min_price", get_min_price)st_env.register_function("format_discount_info", format_discount_info)# querycalculate_func(st_env)# executeprint("提交作业")st_env.execute("item_got_price")

04 总结

工程上线后,由于数据收集端在不停的提供数据,借助流计算,我们已经鉴别出 200 个涉嫌违规定价的商品链接,在维护品牌力和价格力的同时,避免旗舰店销售损失 40 余万,而这只是我们众多监控用 Flink Job 中的一个。

在本着“将企业越做越小,市场越做越大”思路的今天,使用 IT 技术来代替人工作业已经是最快捷的一条路,即便像我们这种小微企业并不像大厂那样是技术主导,只要产出能被业务同事喜欢使用且提高工作效率的功能,同时被公司高层所重视,那我们的工作就是有意义的且可持续的。

如果你也像我们一样,以 Python 语言为主,开发工作多为数据分析和实时决策,又渴望享受流计算带来的准确、高效和便捷,那么,欢迎加入 PyFlink 生态,让我们一起为她的明天添砖加瓦。同时 Flink 1.11 版本也预计将在 6 月中下旬发布,届时 PyFlink 将携 Pandas 强势来袭。

最后,再次感谢在扶持计划中所有帮助过我们的人!总之, PyFlink,你值得拥有。

640 5.png

如果您也对 PyFlink 社区扶持计划感兴趣,可以填写下方问卷,与我们一起共建 PyFlink 生态。

PyFlink 社区扶持计划:

https://survey.aliyun.com/apps/zhiliao/B5JOoruzY

原文链接
本文为云栖社区原创内容,未经允许不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/515656.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

uni-app父子组件间的方法调用及传值

文章目录一、父组件调用子组件里的方法1. 先准备一个子组件2. 准备一个父组件二、子组件调用父组件里的方法2.1. 准备一个父组件2.2. 在准备一个子组件三、父组件给子组件传值3.1. 父组件&#xff1a;3.2. 子组件&#xff1a;四、子组件给父组件传值4.1. 父组件4.2.子组件uni-a…

如何三步搭建一套声纹系统

背景介绍 声纹检索&#xff0c;顾名思义就是说话人识别&#xff0c;通过声音来验证或者识别说话人的声音。声纹识别的关键步骤就是声音向量化&#xff0c;将说话人的声音将其转化成结构化的向量。阿里云AnalyticDB向量版&#xff0c;提供了一套声纹验证检索的解决方案。用户只…

云原生人物志|Pulsar翟佳:社区的信任最重要

云原生已无处不在&#xff0c;《云原生人物志》是CSDN重磅推出的系列原创采访&#xff0c;我们关注云原生中每一个技术人、公司的身影。知微见著&#xff0c;窥见云原生价值与趋势。 编辑 | 宋 慧 出品 | CSDN云计算 头图 | 付费下载于视觉中国 本期我们采访了 Apache 顶级项目…

如何为Kubernetes实现原地升级

作者 | 王思宇&#xff08;酒祝&#xff09; 阿里云技术专家 参与阿里巴巴云原生文末留言互动&#xff0c;即有机会获得赠书福利及作者答疑&#xff01; 概念介绍 原地升级一词中&#xff0c;“升级”不难理解&#xff0c;是将应用实例的版本由旧版替换为新版。那么如何结合…

uniapp实现表单提交带图片上传 在做表单提交的时候,我们可能面临有图片上传,放在原生的html就好解决,form标签加上

enctype“multipart/form-data” uniapp微信小程序 1.原图 页面部分 <form :model"data" submit"submit" reset""><view class"top bgbai u-m-t-30" :class"{disabled: !isaction && data.renz.id}">…

系统架构设计师 - 单体架构、SOA架构、微服务架构

文章目录横向对比SOA设计原则主要技术UDDI 统一描述发现集成SOAP 简单对象访问协议WSDL web服务描述语言BPEL 业务过程执行语言REST 表述性状态转移实现方法WebServiceESB服务注册表主要问题横向对比 单体架构SOA架构微服务架构特点复杂性高、技术债务逐渐上升、部署速度越来越…

Java字符串连接运算符干了什么?

和其他多数程序设计语言一样&#xff0c;Java 语言允许使用 连接两个字符串。 String name "stephen"; String foo "Hey, " name; 当我们将一个字符串和一个非字符串的值进行拼接时&#xff0c;并不会报错&#xff1a; String name "Stephen&…

文件上传问题org.springframework.web.HttpMediaTypeNotSupportedException: Content type ‘multipart/form-data;

接收表单使用对象接收时不要使用注解 /*** 单文件上传&#xff08;微信小程序只支持单文件上传&#xff09;** param file* return* throws Exception*/PostMapping("/filesUpload")public R uploadFile(FormDataReq f, RequestParam("file") MultipartFil…

灵魂拷问:a = 1 + 2 究竟是怎么被 CPU 执行的

来源 | 小林coding作者 | 小林coding头图 | 下载于视觉中国代码写了那么多&#xff0c;你知道 a 1 2 这条代码是怎么被 CPU 执行的吗&#xff1f;软件用了那么多&#xff0c;你知道软件的 32 位和 64 位之间的区别吗&#xff1f;再来 32 位的操作系统可以运行在 64 位的电脑上…

如何利用全站加速,提升网站性能和用户体验?

随着网络技术的发展&#xff0c;越来越多的应用基于互联网发布&#xff0c;再好的应用&#xff0c;如果打开速度慢&#xff0c;10个用户会有9个用户选择离开&#xff0c;相关统计数据显示&#xff0c;每增加0.1秒的加载延迟&#xff0c;将会导致客户活跃度下降1%。在目前获客成…

IDEA 搭建 SpringBoot + Maven + Oracle + Hibernate 项目框架

1.Spring Initializer 创建空项目 2.安装Oracle 3.查询Oracle版本 select * from product_component_version;4.安装Oracle驱动并引入pom 5.添加yml配置文件 server:port: 8989 spring:datasource:driver-class-name: oracle.jdbc.OracleDriverurl: jdbc:oracle:thin:127.0.0…

1418 -This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration

今天在mysql中创建函数的时候&#xff0c;报错如下&#xff1a; ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you might want to use the less safe log_bin_trust_function_…

最近,老王又Get了CDN的新技能

原文链接 本文为云栖社区原创内容&#xff0c;未经允许不得转载。

线程池 总结

文章目录线程池优点线程池创建参数队列种类同步移交队列有界队列无界队列拒绝策略DiscardPolicyAbortPolicyDiscardOldestPolicyCallerRunsPolicy线程池执行流程线程池类型定长 FixedThreadPool轮询 ScheduledThreadPool缓存 CachedThreadPool单线程 SingleThreadPool线程池优点…

阿里的 RocketMQ 如何让双十一峰值之下0故障

作者 | 愈安来源 | 阿里巴巴中间件头图 | 下载于视觉中国2020 年的双十一交易峰值达到 58.3 W笔/秒&#xff0c;消息中间件 RocketMQ 继续数年 0 故障丝般顺滑地完美支持了整个集团大促的各类业务平稳。相比往年&#xff0c;消息中间件 RocketMQ 发生了以下几个方面的变化&…

OAM深入解读:使用OAM定义与管理Kubernetes内置Workload

作者 | 周正喜 阿里云技术专家 爱好云原生&#xff0c;深度参与 OAM 社区 大家都知道&#xff0c;应用开放模型 Open Application Model&#xff08;OAM&#xff09; 将应用的工作负载&#xff08;Workload&#xff09;分为三种 —— 核心型、标准型和扩展型&#xff0c;这三…

oracle 指定类型和指定位数创建序列号

文章目录一、脚本部分1. 表结构2. 函数二、代码部分2.1. xml2.2. 接口2.3. api接口2.4. api实例2.5. 控制层三、测试3.1. 效果图一、脚本部分 1. 表结构 有注释 -- Create table create table LDMAXNO (NOTYPE VARCHAR2(17) not null,NOLIMIT VARCHAR2(12) not null,MAXNO …

深入解读Flink资源管理机制

作者&#xff1a;宋辛童&#xff08;五藏&#xff09;整理&#xff1a;王文杰&#xff08;Flink 社区志愿者&#xff09; 摘要&#xff1a;本文根据 Apache Flink 系列直播整理而成&#xff0c;由阿里巴巴高级开发工程师宋辛童分享。文章主要从基本概念、当前机制与策略、未来发…

EasyExcel 实现模板导出、模板导入分析功能

文章目录0.POM依赖1.导出模板实现2.导入模板并分析实现3.git源码0.POM依赖 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency>…

金蝶云拿下客户满意度第一,中国SaaS企业觅得“后发先至”良机

本月&#xff0c;全球SaaS行业迎来了开年第一份重磅奖项的揭晓&#xff1a;由国际知名研究机构IDC颁发的SaaS行业全球客户满意度奖&#xff08;CSAT大奖&#xff09;。 该奖项基于IDC SaaSPath针对全球约2000家组织机构中高层的调研&#xff0c;综合30多项客户满意度指标&…