范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

Sentinel熔断降级流控生产级改造

  时光闹钟app开发者,请关注我,后续分享更精彩!
  坚持原创,共同进步!前言
  阿里开源Sentinel框架功能强大,实现了对服务的流控、熔断降级,并支持通过管理页面进行配置和监控。Client集成支持Java、Go等语言。但管理后台Dashboard,默认只适合开发和演示,要生产环境使用需要做相应源代码级改造。本文将介绍具体改造步骤,帮助大家更快实现在生产环境的部署应用。当然,如果预算充足,也可以直接使用阿里云开箱即用的Sentinel Dashboard服务。整体架构
  Sentinel Dashboard规则默认存储在内存中,一旦服务重启,规则将丢失。要实现生产环境的大规模应用,需要把规则做持久化存储,Sentinel支持把nacos/zookeeper/apollo/redis等中间件作为存储介质。本文以Nacos作为规则存储端进行介绍。
  整体架构如上图,Sentinel Dashboard通过界面操作,添加资源的规则,保存时将信息推送到nacos中。nacos收到数据变更,并实时推送到应用中的Sentinel SDK客户端,Sentinel SDK应用规则实现对服务资源的流控/熔断/降级管控。代码改造
  Sentinel 使用nacos作为存储端,需要修改源代码。
  1.源代码下载git clone git@github.com:hcq0514/Sentinel.git
  IDE工具打开sentinel-dashboard项目模块
  注意:将项目切换到使用的sentinel tag稳定版本,这里为1.8.6版本
  2.pom.xml添加依赖
  sentinel-dashboard模块pom.xml文件中,把sentinel-datasource-nacos依赖的注释掉。      com.alibaba.csp     sentinel-datasource-nacos      
  3.前端页面修改
  resources/app/scripts/directives/sidebar/sidebar.html文件,将dashboard.flowV1改成dashboard.flow
  • 流控规则
  •   4.Java代码修改   com.alibaba.csp.sentinel.dashboard.rule包中创建一个nacos包,用来存放Nacos相关代码类。   nacos包下创建NacosPropertiesConfiguration类,用于nacos server配置属性封装package com.alibaba.csp.sentinel.dashboard.rule.nacos; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = "sentinel.nacos") public class NacosPropertiesConfiguration { private String namespace; private String serverAddr; private String username; private String password; //省略 属性 set/get 方法...... }   nacos包下创建NacosConfigUtil工具类public final class NacosConfigUtil { public static final String GROUP_ID = "SENTINEL_GROUP"; public static final String FLOW_DATA_ID_POSTFIX = "-flow-rules"; public static final String DEGRADE_DATA_ID_POSTFIX = "-degrade-rules"; public static final String PARAM_FLOW_DATA_ID_POSTFIX = "-param-rules"; public static final String CLUSTER_MAP_DATA_ID_POSTFIX = "-cluster-map"; /** * cc for `cluster-client` */ public static final String CLIENT_CONFIG_DATA_ID_POSTFIX = "-cc-config"; /** * cs for `cluster-server` */ public static final String SERVER_TRANSPORT_CONFIG_DATA_ID_POSTFIX = "-cs-transport-config"; public static final String SERVER_FLOW_CONFIG_DATA_ID_POSTFIX = "-cs-flow-config"; public static final String SERVER_NAMESPACE_SET_DATA_ID_POSTFIX = "-cs-namespace-set"; private NacosConfigUtil() {} }   nacos包创建NacosConfiguration bean配置类@EnableConfigurationProperties(NacosPropertiesConfiguration.class) @Configuration public class NacosConfiguration { @Bean @Qualifier("degradeRuleEntityEncoder") public Converter, String> degradeRuleEntityEncoder() { return JSON::toJSONString; } @Bean @Qualifier("degradeRuleEntityDecoder") public Converter> degradeRuleEntityDecoder() { return s -> JSON.parseArray(s, DegradeRuleEntity.class); } @Bean @Qualifier("flowRuleEntityEncoder") public Converter, String> flowRuleEntityEncoder() { return JSON::toJSONString; } @Bean @Qualifier("flowRuleEntityDecoder") public Converter> flowRuleEntityDecoder() { return s -> JSON.parseArray(s, FlowRuleEntity.class); } @Bean public ConfigService nacosConfigService(NacosPropertiesConfiguration nacosPropertiesConfiguration) throws NacosException { Properties properties = new Properties(); properties.put(PropertyKeyConst.SERVER_ADDR, nacosPropertiesConfiguration.getServerAddr()); if(StringUtils.isNotBlank(nacosPropertiesConfiguration.getNamespace())){ properties.put(PropertyKeyConst.NAMESPACE, nacosPropertiesConfiguration.getNamespace()); } if(StringUtils.isNotBlank(nacosPropertiesConfiguration.getUsername())){ properties.put(PropertyKeyConst.USERNAME, nacosPropertiesConfiguration.getUsername()); } if(StringUtils.isNotBlank(nacosPropertiesConfiguration.getPassword())){ properties.put(PropertyKeyConst.PASSWORD, nacosPropertiesConfiguration.getPassword()); } return ConfigFactory.createConfigService(properties); } }   nacos包下创建流控的provider和publisher实现类@Component("flowRuleNacosProvider") public class FlowRuleNacosProvider implements DynamicRuleProvider> { @Autowired private ConfigService configService; @Autowired @Qualifier("flowRuleEntityDecoder") private Converter> converter; @Override public List getRules(String appName) throws Exception { String rules = configService.getConfig(appName + NacosConfigUtil.FLOW_DATA_ID_POSTFIX, NacosConfigUtil.GROUP_ID, 3000); if (StringUtil.isEmpty(rules)) { return new ArrayList<>(); } return converter.convert(rules); } }@Component("flowRuleNacosPublisher") public class FlowRuleNacosPublisher implements DynamicRulePublisher> { @Autowired private ConfigService configService; @Autowired @Qualifier("flowRuleEntityEncoder") private Converter, String> converter; @Override public void publish(String app, List rules) throws Exception { AssertUtil.notEmpty(app, "app name cannot be empty"); if (rules == null) { return; } configService.publishConfig(app + NacosConfigUtil.FLOW_DATA_ID_POSTFIX, NacosConfigUtil.GROUP_ID, converter.convert(rules)); } }   nacos包下创建熔断/降级的provider和publisher实现类@Component("degradeRuleNacosProvider") public class DegradeRuleNacosProvider implements DynamicRuleProvider> { @Autowired private ConfigService configService; @Autowired @Qualifier("degradeRuleEntityDecoder") private Converter> converter; @Override public List getRules(String appName) throws Exception { String rules = configService.getConfig(appName + NacosConfigUtil.DEGRADE_DATA_ID_POSTFIX, NacosConfigUtil.GROUP_ID, 3000); if (StringUtil.isEmpty(rules)) { return new ArrayList<>(); } return converter.convert(rules); } }@Component("degradeRuleNacosPublisher") public class DegradeRuleNacosPublisher implements DynamicRulePublisher> { @Autowired private ConfigService configService; @Autowired @Qualifier("degradeRuleEntityEncoder") private Converter, String> converter; @Override public void publish(String app, List rules) throws Exception { AssertUtil.notEmpty(app, "app name cannot be empty"); if (rules == null) { return; } configService.publishConfig(app + NacosConfigUtil.DEGRADE_DATA_ID_POSTFIX, NacosConfigUtil.GROUP_ID, converter.convert(rules)); } }   修改com.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2类。将注入的bean标识由下图右边替换左边的值。将原有的服务引用基于内存存储,替换为nacos存储的服务引用。# 上面截图红框替换值 flowRuleDefaultProvider 替换为 flowRuleNacosProvider flowRuleDefaultPublisher 替换为 flowRuleNacosPublisher   删除com.alibaba.csp.sentinel.dashboard.controller.DegradeController类, com.alibaba.csp.sentinel.dashboard.controller.v2包下新增DegradeControllerV2类@RestController @RequestMapping("/degrade") public class DegradeControllerV2 { private final Logger logger = LoggerFactory.getLogger(DegradeControllerV2.class); @Autowired private RuleRepository repository; @Autowired @Qualifier("degradeRuleNacosProvider") private DynamicRuleProvider> ruleProvider; @Autowired @Qualifier("degradeRuleNacosPublisher") private DynamicRulePublisher> rulePublisher; @GetMapping("/rules.json") @AuthAction(PrivilegeType.READ_RULE) public Result> apiQueryMachineRules(String app, String ip, Integer port) { if (StringUtil.isEmpty(app)) { return Result.ofFail(-1, "app can"t be null or empty"); } if (StringUtil.isEmpty(ip)) { return Result.ofFail(-1, "ip can"t be null or empty"); } if (port == null) { return Result.ofFail(-1, "port can"t be null"); } try { // List rules = sentinelApiClient.fetchDegradeRuleOfMachine(app, ip, port); List rules = ruleProvider.getRules(app); if (rules != null && !rules.isEmpty()) { for (DegradeRuleEntity entity : rules) { entity.setApp(app); } } rules = repository.saveAll(rules); return Result.ofSuccess(rules); } catch (Throwable throwable) { logger.error("queryApps error:", throwable); return Result.ofThrowable(-1, throwable); } } @PostMapping("/rule") @AuthAction(PrivilegeType.WRITE_RULE) public Result apiAddRule(@RequestBody DegradeRuleEntity entity) { Result checkResult = checkEntityInternal(entity); if (checkResult != null) { return checkResult; } Date date = new Date(); entity.setGmtCreate(date); entity.setGmtModified(date); try { entity = repository.save(entity); } catch (Throwable t) { logger.error("Failed to add new degrade rule, app={}, ip={}", entity.getApp(), entity.getIp(), t); return Result.ofThrowable(-1, t); } if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) { logger.warn("Publish degrade rules failed, app={}", entity.getApp()); } return Result.ofSuccess(entity); } @PutMapping("/rule/{id}") @AuthAction(PrivilegeType.WRITE_RULE) public Result apiUpdateRule(@PathVariable("id") Long id, @RequestBody DegradeRuleEntity entity) { if (id == null || id <= 0) { return Result.ofFail(-1, "id can"t be null or negative"); } DegradeRuleEntity oldEntity = repository.findById(id); if (oldEntity == null) { return Result.ofFail(-1, "Degrade rule does not exist, id=" + id); } entity.setApp(oldEntity.getApp()); entity.setIp(oldEntity.getIp()); entity.setPort(oldEntity.getPort()); entity.setId(oldEntity.getId()); Result checkResult = checkEntityInternal(entity); if (checkResult != null) { return checkResult; } entity.setGmtCreate(oldEntity.getGmtCreate()); entity.setGmtModified(new Date()); try { entity = repository.save(entity); } catch (Throwable t) { logger.error("Failed to save degrade rule, id={}, rule={}", id, entity, t); return Result.ofThrowable(-1, t); } if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) { logger.warn("Publish degrade rules failed, app={}", entity.getApp()); } return Result.ofSuccess(entity); } @DeleteMapping("/rule/{id}") @AuthAction(PrivilegeType.DELETE_RULE) public Result delete(@PathVariable("id") Long id) { if (id == null) { return Result.ofFail(-1, "id can"t be null"); } DegradeRuleEntity oldEntity = repository.findById(id); if (oldEntity == null) { return Result.ofSuccess(null); } try { repository.delete(id); } catch (Throwable throwable) { logger.error("Failed to delete degrade rule, id={}", id, throwable); return Result.ofThrowable(-1, throwable); } if (!publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) { logger.warn("Publish degrade rules failed, app={}", oldEntity.getApp()); } return Result.ofSuccess(id); } private boolean publishRules(String app, String ip, Integer port) { /*List rules = repository.findAllByMachine(MachineInfo.of(app, ip, port)); return sentinelApiClient.setDegradeRuleOfMachine(app, ip, port, rules);*/ List rules = repository.findAllByApp(app); try { rulePublisher.publish(app, rules); } catch (Exception e) { logger.error("Failed to publish nacos, app={}", app); logger.error("error is : ",e); } return true; } private Result checkEntityInternal(DegradeRuleEntity entity) { if (StringUtil.isBlank(entity.getApp())) { return Result.ofFail(-1, "app can"t be blank"); } if (StringUtil.isBlank(entity.getIp())) { return Result.ofFail(-1, "ip can"t be null or empty"); } if (entity.getPort() == null || entity.getPort() <= 0) { return Result.ofFail(-1, "invalid port: " + entity.getPort()); } if (StringUtil.isBlank(entity.getLimitApp())) { return Result.ofFail(-1, "limitApp can"t be null or empty"); } if (StringUtil.isBlank(entity.getResource())) { return Result.ofFail(-1, "resource can"t be null or empty"); } Double threshold = entity.getCount(); if (threshold == null || threshold < 0) { return Result.ofFail(-1, "invalid threshold: " + threshold); } Integer recoveryTimeoutSec = entity.getTimeWindow(); if (recoveryTimeoutSec == null || recoveryTimeoutSec <= 0) { return Result.ofFail(-1, "recoveryTimeout should be positive"); } Integer strategy = entity.getGrade(); if (strategy == null) { return Result.ofFail(-1, "circuit breaker strategy cannot be null"); } if (strategy < CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType() || strategy > RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT) { return Result.ofFail(-1, "Invalid circuit breaker strategy: " + strategy); } if (entity.getMinRequestAmount() == null || entity.getMinRequestAmount() <= 0) { return Result.ofFail(-1, "Invalid minRequestAmount"); } if (entity.getStatIntervalMs() == null || entity.getStatIntervalMs() <= 0) { return Result.ofFail(-1, "Invalid statInterval"); } if (strategy == RuleConstant.DEGRADE_GRADE_RT) { Double slowRatio = entity.getSlowRatioThreshold(); if (slowRatio == null) { return Result.ofFail(-1, "SlowRatioThreshold is required for slow request ratio strategy"); } else if (slowRatio < 0 || slowRatio > 1) { return Result.ofFail(-1, "SlowRatioThreshold should be in range: [0.0, 1.0]"); } } else if (strategy == RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO) { if (threshold > 1) { return Result.ofFail(-1, "Ratio threshold should be in range: [0.0, 1.0]"); } } return null; } }   5.maven打包   重新打包sentinel-dashboard模块mvn clean package   6.配置文件修改   application.properties添加nacos配置项#nacos服务地址 sentinel.nacos.serverAddr=127.0.0.1:8848 #nacos命名空间 sentinel.nacos.namespacec= #sentinel.nacos.username= #sentinel.nacos.password=应用端集成   1.引入依赖 com.alibaba.cloud spring-cloud-starter-alibaba-sentinel   如果是maven多模块工程,父pom中添加alibaba的父pom依赖 com.alibaba.cloud spring-cloud-alibaba-dependencies 2.2.6.RELEASE pom import   2.注解支持   Sentinel 提供了 @SentinelResource 注解用于定义资源,实现资源的流控/熔断降级处理。   注意:注解方式埋点不支持 private 方法。@Service @Slf4j public class TestService { /** * 定义sayHello资源的方法,流控/熔断降级处理逻辑 * @param name * @return */ @SentinelResource(value = "sayHello",blockHandler = "sayHelloBlockHandler",fallback = "sayHelloFallback") public String sayHello(String name) { if("fallback".equalsIgnoreCase(name)){ throw new RuntimeException("fallback"); } return "Hello, " + name; } /** * 被流控后处理方法。 * 1. @SentinelResource 注解blockHandler设置,值为函数方法名 * 2. blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。 * 3. blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。 * @param name * @param blockException * @return */ public String sayHelloBlockHandler(String name, BlockException blockException){ log.warn("已开启流控",blockException); return "流控后的返回值"; } /** * 被降级后处理方法 * 注意!!!:如果blockHandler和fallback都配置,熔断降级规则生效,触发熔断,在熔断时长定义时间内,只有blockHandler生效 * 1. @SentinelResource 注解fallback设置,值为函数方法名 * 2. 用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理 * 3. 返回值类型必须与原函数返回值类型一致; * 4. 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。 * 5. allback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。 * @param name * @param throwable * @return */ public String sayHelloFallback(String name, Throwable throwable){ log.warn("已降级",throwable); return "降级后的返回值"; } }   流控和降级处理逻辑定义详见代码注释。   @SentinelResource还包含其他可能使用的属性:exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。exceptionsToTrace:用于指定处理的异常。默认为Throwable.class。可设置自定义需要处理的其他异常类。   3.添加配置   application.yml文件添加以下配置spring: application: name: demo-sentinel cloud: sentinel: #阿里sentinel配置项 transport: # spring.cloud.sentinel.transport.port 端口配置会在应用对应的机器上启动一个 Http Server, # 该 Server 会与 Sentinel 控制台做交互。比如 Sentinel 控制台添加了一个限流规则,会把规则数据 push 给这个 Http Server 接收, # Http Server 再将规则注册到 Sentinel 中。 # port: 8719 dashboard: localhost:8080 datasource: ds1: # 数据源标识key,可以随意命名,保证唯一即可 nacos: #nacos 数据源-流控规则配置 server-addr: localhost:8848 # username: nacos # password: nacos data-id: ${spring.application.name}-flow-rules group-id: SENTINEL_GROUP data-type: json #flow、degrade、param-flow rule-type: flow ds2: nacos: #nacos 数据源-熔断降级规则配置 server-addr: localhost:8848 # username: nacos # password: nacos data-id: ${spring.application.name}-degrade-rules group-id: SENTINEL_GROUP data-type: json #flow、degrade、param-flow rule-type: degrade验证   启动sentinel-dashboard。   应用端集成Sentinel SDK,访问添加了降级逻辑处理的接口地址。   访问sentinel-dashboard web页面: http://localhost:8080/ 。在界面,添加相应流控和熔断规则。   Nacos管理界面查看:http://localhost:8848/nacos 。 可以看到自动生成了两个配置界面,分别对应流控和熔断配置   点击规则详情,查看规则信息   规则json对象信息如下:[ { "app": "***-sentinel", "clusterConfig": { "acquireRefuseStrategy": 0, "clientOfflineTime": 2000, "fallbackToLocalWhenFail": true, "resourceTimeout": 2000, "resourceTimeoutStrategy": 0, "sampleCount": 10, "strategy": 0, "thresholdType": 0, "windowIntervalMs": 1000 }, "clusterMode": false, "controlBehavior": 0, "count": 4000, "gmtCreate": 1677065845653, "gmtModified": 1677065845653, "grade": 1, "id": 1, "ip": "192.168.56.1", "limitApp": "default", "port": 8720, "resource": "sayHello2", "strategy": 0 }, { "app": "***-sentinel", "clusterConfig": { "acquireRefuseStrategy": 0, "clientOfflineTime": 2000, "fallbackToLocalWhenFail": true, "resourceTimeout": 2000, "resourceTimeoutStrategy": 0, "sampleCount": 10, "strategy": 0, "thresholdType": 0, "windowIntervalMs": 1000 }, "clusterMode": false, "controlBehavior": 0, "count": 1000, "gmtCreate": 1677057866855, "gmtModified": 1677065997762, "grade": 1, "id": 3, "ip": "192.168.56.1", "limitApp": "default", "port": 8720, "resource": "sayHello", "strategy": 0 }, { "app": "***-sentinel", "clusterConfig": { "acquireRefuseStrategy": 0, "clientOfflineTime": 2000, "fallbackToLocalWhenFail": true, "resourceTimeout": 2000, "resourceTimeoutStrategy": 0, "sampleCount": 10, "strategy": 0, "thresholdType": 0, "windowIntervalMs": 1000 }, "clusterMode": false, "controlBehavior": 0, "count": 2, "gmtCreate": 1677117433499, "gmtModified": 1677117433499, "grade": 1, "id": 6, "ip": "192.168.56.1", "limitApp": "default", "port": 8720, "resource": "/ping", "strategy": 0 } ]

    女运动员比赛服被指露骨,专业运动服与日常服饰有哪些区别?近日,国家一级运动员阿爽因参加铁人三项比赛穿的紧身运动服,遭网友批评穿泳衣参赛,过于露骨,不得体。事后,阿爽公开回应称,所穿运动服并非泳衣,而是比赛专用铁三服。业内人士称,该运动员孙杨世界纪录获得认可!引热议,央视人民日报态度说明一切9月23日,许久未在公共场合露面的孙杨再次登上热搜,成为国内媒体网友关注的焦点!22日,孙杨在个人社交平台发布上与网友分享了自己的世界纪录证书,并且配文写道10年,世界纪录证书游来女运动员穿铁三服被指太露骨,该运动员的着装符合规定女运动员穿铁三服被指太露骨,该运动员的着装符合规定女运动员穿铁三服被指太露骨近日,国家一级运动员阿爽因穿着泳装参加铁人三项比赛被网友批评,过于露骨和不妥。随后,阿爽公开回应称,他穿朝鲜观察,朝鲜普通人过着怎样的小日子?到朝鲜旅游,能感受到朝鲜人的生活不富裕,他们的衣食住行和我们八十年代差不多。据朝鲜导游透露,朝鲜普通上班族的工资折算成人民币每个月三四百块。在朝鲜的几天时间,我发现朝鲜人的生活没有女运动员铁三比赛服被指太露骨,家属回应很多人不懂,都在看热闹近日,原国家铁人三项队队员阿爽参加铁人三项比赛所穿的铁三服被指像泳衣太露骨,业内人士称,该运动员着装符合规定。23日下午,阿爽家属回应记者称,阿爽几年前已从国家队退役,参加这次比赛上半年车企成绩单出炉,自主品牌和新能源扛上了导语现在新能源汽车大行其道,因此很多人都觉得除了那些新能源汽车企业之外,大部分车企都没有比较好的效益,但是从最近自主品牌公布的财报来看,事实好像并不是像大家所预想的那样。各大传统自82家财险公司期中成绩单人保赚一半,平安赚1482家财险公司披露半年数据保费合计7964亿元同比增长9。2净利润合计386亿元同比增长6。1人保利润占行业的49平安利润占行业的24未公布利润的有大家财险天安财险易安财险Atte今秋最帅男发15款,百变时尚很有型,越剪越精神既然你我相遇,那就是缘分,关注时尚,关注发型,关注刘丽丽秋天什么样的男士发型比较好呢?如果你还不清楚,可以看看今天为大家带来的今秋最帅男发15款,百变时尚很有型,越剪越精神。男士发体验消费时代来临,看林清轩如何蓄能发力线下门店服务?文章转载自凤凰网今年大家谈的最多的一个词就是内卷,让我们看看内卷的美妆界战况激烈,国货美妆品牌面对国际大牌的竞争,展现出了强劲的增长力。并且在高端美妆市场,国货美妆品牌的市场份额与成分党必知EGF想要有效护肤,当然不可避免地要具有一定的成分观念,不单单看产品的宣传,更要看产品的成分,今天我们来唠一下护肤品成分之EGF。EGF是什么EGF也就是表皮生长因子,学名人寡肽1是一种谁是最美女神坐在街口的咖啡厅,看着窗外热闹的三八节活动,您突然问我谁是你的女神?我的女神?我沉思了从我成功孕育那天开始,您娇小的身躯变得日益沉重,白净的脸庞现出了斑点,爱美的您剪断了飘逸的青丝
    (体育)乒乓球成都世乒赛德国女队晋级四强当日,在成都举行的第56届世界乒乓球团体锦标赛(决赛)女子四分之一决赛中,德国队以3比2战胜中国香港队,晋级四强。10月6日,中国香港队选手朱成竹在比赛中回球,她以3比1战胜德国队中国芯片能否弯道超车?还是自娱自乐?又是一个令人无比振奋的好消息,最近中国研发的碳基芯片彻底震惊了西方媒体,因为这将会颠覆芯片半导体的整个市场格局,中国芯片再也不用担心卡脖子问题了。现实中科院宣布研发了八英寸的石墨烯麒麟芯片重生!首发应该是麒麟8305G版本华为Mate50只有4G版,实在是一件丢人的事。余承东也说,作为5G领导者,却没有5G手机发布,尴尬。在美国制裁之下,明知麒麟芯片强于高通,但只能选用高通芯片,更是丢人。当然,用丢98ampamp39ampamp39Q10G大国品牌算法超前在科技的洪流之中,任何一款产品避免不了谈及其芯片,而TCL9月上新98Q10G在自主的芯片算法上,优势巨显,算法超前。TCL中环TCL中环新能源科技股份有限公司长期专注于半导体和新智慧农业信息化建设解决方案来源网络什么是智慧农业智慧农业是通过云计算传感网3S等多种信息技术在农业中综合全面的应用,实现更完备的信息化基础支撑更透彻的农业信息感知。依托部署在农业生产现场的各种传感节点(环境今日摘抄分享今天偶然看到一段话,觉得挺有道理的,就摘抄下来分享给大家。不要像个落难者,告诉所有人你的不幸。总有一天你会明白,你的委屈要自己消化,你的故事不用逢人就讲起,真正理解的你没有几个,大知识储备之用py2app将Python代码打包成MacOS可用的APP自己电脑上有完整的python环境,所以偶尔写个小工具什么的都很easy,直接命令行run一波就OK,但是如果需要再朋友的电脑上运行,帮别人写了一个小工具,他没有运行环境,就很麻烦小源说金10。5金价谨慎追高!今日黄金走势分析及操作思路基本面目前市场担心美联储过快的加息可能导致利率上升,给经济带来一定的衰退压力。导致11月加息50基点概率上升,黄金上涨超过1。6,触及1730的高点。此外根据外媒报道,在北溪管道泄VR学车帮助驾校降低4成运营成本视频加载中随着VR技术的发展,VR得到了广泛的应用,为各产业带来了重大的积极影响。尤其是在传统驾培领域,VR学车带来了颠覆性的改变,完全改变了传统单一的学车方式,让学车体验更舒适更康熙第一次大封后宫,9位妃子个个不简单,还有2位神秘失踪排版丨青黛编辑丨后宫冷婶儿康熙第一次大封后宫,这9个女人个个不简单!康熙十六年八月二十二日,康熙后宫迎来了第一次大升迁,这次总共升职了9个妃子。三年前,康熙的原配赫舍里皇后去世后,小红书最火的副业,凭啥月入8万每年都有爆火的副业,而今年的网红副业似乎轮到了线上酒馆。这种小酒馆没有实体店,售卖酒馆常见的酒水饮料,还搭配零食骰子等,看起来好像是一个稳赚不赔的小体量创业项目。然而,真的是这样吗