主頁 > 軟體設計 > 秒殺鏈路兜底方案之限流&降級實戰

秒殺鏈路兜底方案之限流&降級實戰

2021-10-13 07:55:56 軟體設計

前言:學習本篇博客是有一些前提基礎的
1、熟悉gateway網關使用
2、熟悉nginx使用
3、熟悉sentinel的應用,會涉及網關規則持久化改造
看不懂的童鞋們可以補一下微服務gateway網關和Sentinel相關知識

秒殺鏈路兜底方案之限流&降級實戰

  • 一、秒殺場景介紹
    • 1.1 秒殺場景的特點
    • 1.2 流量消峰
    • 1.3 兜底方案
  • 二、限流實戰
    • 2.1 nginx限流(https://nginx.org/en/docs)
    • 2.2 網關限流
      • 2.2.1 網關接入sentinel控制臺
      • 2.2.2 Sentinel規則持久化配置
    • 2.3 應用層限流
  • 三、降級實戰
    • 3.1 服務降級的策略
    • 3.2 應用層降級實戰
  • 四、拒絕服務

一、秒殺場景介紹

1.1 秒殺場景的特點

  • 秒殺具有瞬時高并發的特點,秒殺請求在時間上高度集中于某一特定的時間點(秒殺開始那一秒),這樣一來,就會導致一個特別高 的流量峰值,它對資源的消耗是瞬時的,
  • 但是對秒殺這個場景來說,最終能夠搶到商品的人數是固定的,也就是說 100 人和 10000 人發起請求的結果都是一樣的,并發度越高,無效請求也越多
  • 但是從業務上來說,秒殺活動是希望更多的人來參與的,也就是開始之前希望有更多的人來刷頁面,但是真正開始下單時,秒殺請求 并不是越多越好,

1.2 流量消峰

服務器的處理資源是恒定的,你用或者不用它的處理能力都是一樣的,所以出現峰值的話,很容易導致忙到處理不過來,閑的時候卻又沒有什么要處理,
流量削峰,一是可以讓服務端處理變得更加平穩,二是可以節省服務器的資源成本,針對秒殺這一場景,削峰從本質 上來說就是更多地延緩用戶請求的發出,以便減少和過濾掉一些無效請求,它遵從“請求數要盡量少”的原則,流量削峰的比較常見的 思路:排隊、答題、分層過濾

1.3 兜底方案

對于很多秒殺系統而言,在諸如雙十一這樣的大流量的迅猛沖擊下,都曾經或多或少發生過宕機的情況,當一個系統面臨持續的大流 量時,它其實很難單靠自身調整來恢復狀態,你必須等待流量自然下降或者人為地把流量切走才行,這無疑會嚴重影響用戶的購物體驗, 我們可以在系統達到不可用狀態之前就做好流量限制,防止最壞情況的發生,針對秒殺系統,在遇到大流量時,更多考慮的是運行階段如何保障系統的穩定運行,常用的手段:限流,降級,拒絕服務,

二、限流實戰

限流相對降級是一種更極端的保存措施,限流就是當系統容量達到瓶頸時,我們需要通過限制一部分流量來保護系統,并做到既可以 人工執行開關,也支持自動化保護的措施,

限流既可以是在客戶端限流,也可以是在服務端限流,限流的實作方式既要支持 URL 以及方法級別的限流,也要支持基于 QPS 和線 程的限流,

  • 客戶端限流
    好處:可以限制請求的發出,通過減少發出無用請求從而減少對系統的消耗,
    缺點:當客戶端比較分散時,沒法設定合理的限流閾值:如果閾值設的太小,會導致服務端沒有達到瓶頸時客戶端已經被限制;而如 果設的太大,則起不到限制的作用,
  • 服務端限流
    好處:可以根據服務端的性能設定合理的閾值
    缺點:被限制的請求都是無效的請求,處理這些無效的請求本身也會消耗服務器資源,

在限流的實作手段上來講,基于 QPS 和執行緒數的限流應用最多,最大 QPS 很容易通過壓測提前獲取,例如我們的系統最高支持 1w QPS 時,可以設定 8000 來進行限流保護,執行緒數限流在客戶端比較有效,例如在遠程呼叫時我們設定連接池的執行緒數,超出這個并發線 程請求,就將執行緒進行排隊或者直接超時丟棄,

限流必然會導致一部分用戶請求失敗,因此在系統處理這種例外時一定要設定超時時間,防止因被限流的請求不能 fast fail(快速失 敗)而拖垮系統,

限流的方案

  • 前端限流
  • 接入層nginx限流
  • 網關限流
  • 應用層限流

2.1 nginx限流(https://nginx.org/en/docs)

# window下nginx強制關閉命令
taskkill /fi "imagename eq nginx.EXE" /f 
# 啟動nginx
start nginx.exe 
# 重新加載配置
nginx.exe ‐s reload

limit_conn_zone&limit_conn
ngx_http_limit_conn_module 可以對于一些服務器流量例外、負載過大,甚至是大流量的惡意攻擊訪問等,進行并發數 的限制;該模塊可以根據定義的鍵來限制每個鍵值的連接數,只有那些正在被處理的請求(這些請求的頭資訊已被完全 讀入)所在的連接才會被計數,

# 限制連接數
limit_conn_zone $binary_remote_addr zone=addr:10m;
server {
location /download/ {
# 指定每個給定鍵值的最大同時連接數,同一IP同一時間只允許有1個連接
limit_conn addr 1;
}

客戶端的IP地址作為鍵, binary_remote_addr變數的長度是固定的4位元組,存盤狀態在32位平臺中占用32位元組或64位元組,在64位平臺中占用64位元組, 1M共享空間可以保存3.2萬個32位的狀態,1.6萬個64位的狀態, 如果共享記憶體空間被耗盡,服務器將會對后續所有的請求回傳 503 (Service Temporarily Unavailable) 錯誤,

缺陷: 前端做LVS或反向代理,會出現大量的503錯誤,需要設定白名單(對某些ip不做限制) 測驗: http://localhost/pms/productInfo/29

在這里插入圖片描述

limit_req_zone&limit_req
通過ngx_http_limit_req_module 模塊可以通過定義的鍵值來限制請求處理的頻率,特別的,可以限制來自單個IP地址 的請求處理頻率, 限制的方法如同漏斗,每秒固定處理請求數,推遲過多請求,

http {
# 限制請求數,大小為10m, 平均處理的頻率不能超過每秒1次 
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
... 
server { 
...
location /search/ {
# 允許超出頻率限制的請求數為5,默認會被延遲處理,如果不希望延遲處理,可以使用nodelay引數
limit_req zone=one burst=5 nodelay;
} 

區域名稱為one,大小為10m,平均處理的請求頻率不能超過每秒一次,鍵值是客戶端IP, 使用$binary_remote_addr變數,可以將每條狀態記錄的大小減少到64個位元組,這樣1M的記憶體可以保存大約1萬6千個64位元組的記錄 如果限制域的存盤空間耗盡了,對于后續所有請求,服務器都會回傳503(Service Temporarily Unavailable)錯誤 速度可以設定為每秒處理請求數和每分鐘處理請求數,其值必須是整數,所以如果你需要每秒處理少于1個的請求,2秒處理一個請 求,可以使用30r/m

測驗:
在這里插入圖片描述
在這里插入圖片描述
利用Lua限流

https://github.com/openresty/lua-resty-limit-traffic

2.2 網關限流

spring cloud gateway接入sentinel實作限流的原理:
在這里插入圖片描述

2.2.1 網關接入sentinel控制臺

建議sentinel 控制臺和微服務sentinel版本一一對應,否則可能出現兼容性問題導致規則配置失效

引入依賴

<!‐‐添加Sentinel的依賴‐‐>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring‐cloud‐starter‐alibaba‐sentinel</artifactId>
</dependency>
<!‐‐ gateway接入sentinel ‐‐>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring‐cloud‐alibaba‐sentinel‐gateway</artifactId>
</dependency>

接入sentinel控制臺,修改application.yml配置

spring: 
application: 
name: tulingmall‐gateway
main: 
allow‐bean‐definition‐overriding: true
cloud: 
sentinel: 
transport: 
dashboard: 127.0.0.1:8000

啟動sentinel控制臺

 java ‐Dserver.port=8000 ‐Dsentinel.nacos.config.serverAddr=tl.nacos.com:8848 ‐jar sentinel‐dashboard‐1.7.1.jar

網關接入控制臺后界面展示:
在這里插入圖片描述
Sentinel1.7.1版本,gateway網關規則不生效的問題根本原因: SlotChain中沒有添加GatewayFlowSlot ,默認生效的是HotParamSlotChainBuilder

在這里插入圖片描述

解決思路: 使用GatewaySlotChainBuilder,將GatewayFlowSlot加入到SlotChain 可以利用SPI實作:在當前微服務添加GatewaySlotChainBuilder的spi檔案
在這里插入圖片描述
Sentinel1.8.0 中SlotChain處理策略,統一在DefaultSlotChainBuilder中處理了

在這里插入圖片描述

2.2.2 Sentinel規則持久化配置

在這里插入圖片描述
引入依賴

<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel‐datasource‐nacos</artifactId>
</dependency>

application.yml添加datasource配置

spring:
cloud:
sentinel:
transport:
# 添加sentinel的控制臺地址
dashboard: 127.0.0.1:8000
datasource:
gateway‐flow‐rules:
nacos:
server‐addr: 127.0.0.1:8848
dataId: ${spring.application.name}‐gateway‐flow‐rules
groupId: SENTINEL_GROUP
data‐type: json
rule‐type: gw‐flow
gateway‐api‐rules:
nacos:
server‐addr: 127.0.0.1:8848
dataId: ${spring.application.name}‐gateway‐api‐rules
groupId: SENTINEL_GROUP
data‐type: json
rule‐type: gw‐api‐group

啟動持久化改造后的sentinel dashboard
指定埠和nacos配置中心地址

java ‐Dserver.port=8000 ‐Dsentinel.nacos.config.serverAddr=tl.nacos.com:8848 ‐jar tuling‐sentinel‐dashboard.jar

注意:網關規則改造的坑

  • 網關規則物體轉換
RuleEntity‐‐‐》Rule 利用RuleEntity#toRule
#網關規則物體
ApiDefinitionEntity‐‐‐》ApiDefinition 利用ApiDefinitionEntity#toApiDefinition 
GatewayFlowRuleEntity‐‐‐‐‐>GatewayFlowRule 利用GatewayFlowRuleEntity#toGatewayFlowRule
  • json決議丟失資料
    json決議ApiDefinition型別出現資料丟失的現象
    在這里插入圖片描述
    排查原因: ApiDefinition的屬性Set<ApiPredicateItem> predicateItems中元素 是介面型別,JSON決議丟失數 據
    在這里插入圖片描述
    解決方案:重寫物體類ApiDefinition2,再轉換為ApiDefinition
//GatewayApiRuleNacosProvider.java

@Override
public List<ApiDefinitionEntity> getRules(String appName,String ip,Integer port)throws Exception{
        String rules=configService.getConfig(appName+NacosConfigUtil.GATEWAY_API_DATA_ID_POSTFIX,
        NacosConfigUtil.GROUP_ID,NacosConfigUtil.READ_TIMEOUT);
        if(StringUtil.isEmpty(rules)){
        return new ArrayList<>();
        }

        // 注意 ApiDefinition的屬性Set<ApiPredicateItem> predicateItems中元素 是介面型別,JSON決議丟失資料
        // 重寫物體類ApiDefinition2,再轉換為ApiDefinition
        List<ApiDefinition2> list=JSON.parseArray(rules,ApiDefinition2.class);

        return list.stream().map(rule ‐>
        ApiDefinitionEntity.fromApiDefinition(appName,ip,port,rule.toApiDefinition()))
        .collect(Collectors.toList());
        }

public class ApiDefinition2 {
    private String apiName;
    private Set<ApiPathPredicateItem> predicateItems;

    public ApiDefinition2() {
    }

    public String getApiName() {
        return apiName;
    }

    public void setApiName(String apiName) {
        this.apiName = apiName;
    }

    public Set<ApiPathPredicateItem> getPredicateItems() {
        return predicateItems;
    }

    public void setPredicateItems(Set<ApiPathPredicateItem> predicateItems) {
        this.predicateItems = predicateItems;
    }

    @Override
    public String toString() {
        return "ApiDefinition2{" + "apiName='" + apiName + '\'' + ", predicateItems=" + predicateItems + '}';
    }


    public ApiDefinition toApiDefinition() {
        ApiDefinition apiDefinition = new ApiDefinition();
        apiDefinition.setApiName(apiName);

        Set<ApiPredicateItem> apiPredicateItems = new LinkedHashSet<>();
        apiDefinition.setPredicateItems(apiPredicateItems);

        if (predicateItems != null) {
            for (ApiPathPredicateItem predicateItem : predicateItems) {
                apiPredicateItems.add(predicateItem);
            }
        }

        return apiDefinition;
    }
}

從 1.6.0 版本開始,Sentinel 提供了 Spring Cloud Gateway 的適配模塊,可以提供兩種資源維度的限流:

  • route 維度:即在 Spring 組態檔中配置的路由條目,資源名為對應的 routeId
  • 自定義 API 維度:用戶可以利用 Sentinel 提供的 API 來自定義一些 API 分組

route維度限流
配置流控規則
在這里插入圖片描述
測驗:http://localhost:8888/pms/productInfo/29

在這里插入圖片描述
API維度限流
配置流控規則
在這里插入圖片描述

2.3 應用層限流

場景: 商品詳情介面
系統第一次上線啟動,或者系統在 redis 故障的情況下重新啟動,這時在高并發的場景下就會出現所有的流量 都會打到 mysql(原始資料庫) 上去,導致 mysql 崩潰,因此需要通過快取預熱的方案,提前給 redis 灌入部分資料后再提供服務,

jemeter測驗: 模擬2秒內查詢商品id為1-5000的商品資訊 【/pms/productInfo/${__counter(,)}】
在這里插入圖片描述
壓測直接訪問DB的介面: 吞吐量:20-60

public PmsProductParam getProductInfo1(Long id){
        PmsProductParam productInfo=portalProductDao.getProductInfo(id);
        if(null==productInfo){
        return null;
        }
        checkFlash(id,productInfo);
        return productInfo;
        }

在這里插入圖片描述
壓測訪問快取的介面:

public PmsProductParam getProductInfo2(Long id){
        PmsProductParam productInfo=null;
        // 查詢本地快取 
        productInfo=cache.get(RedisKeyPrefixConst.PRODUCT_DETAIL_CACHE+id);
        if(null!=productInfo){
        return productInfo;
        }
        // 查詢redis快取 
        productInfo=redisOpsUtil.get(RedisKeyPrefixConst.PRODUCT_DETAIL_CACHE+id,PmsProductParam.class);
        if(productInfo!=null){
        //設定本地快取 
        cache.setLocalCache(RedisKeyPrefixConst.PRODUCT_DETAIL_CACHE+id,productInfo);
        return productInfo;
        }
        // 查詢DB 
        productInfo=portalProductDao.getProductInfo(id);
        if(null==productInfo){
        return null;
        }
        checkFlash(id,productInfo);
        // 設定redis快取
        redisOpsUtil.set(RedisKeyPrefixConst.PRODUCT_DETAIL_CACHE+id,productInfo,3600,TimeUnit.SECONDS);
        // 設定本地緩
        cache.setLocalCache(RedisKeyPrefixConst.PRODUCT_DETAIL_CACHE+id,productInfo);
        return productInfo;
        }

第一次訪問快取擊穿的吞吐量: 20-60
之后吞吐量: 1000-2800
在這里插入圖片描述
思考: 在沒有事先進行快取預熱的情況下,如何避免更多的請求直接訪問到資料庫?

當對資料庫訪問達到閾值,可以對商品詳情請求限流
配置流控規則
在這里插入圖片描述
思考:排隊等待可以應用于什么場景?

勻速排隊(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式會嚴格控制請求通過的間隔時間,也即是讓請 求以均勻的速度通過,對應的是漏桶演算法,

該方式的作用如下圖所示:
在這里插入圖片描述
這種方式主要用于處理間隔性突發的流量,例如訊息佇列,想象一下這樣的場景,在某一秒有大量的請求到來,而接下 來的幾秒則處于空閑狀態,我們希望系統能夠在接下來的空閑期間逐漸處理這些請求,而不是在第一秒直接拒絕多余的 請求,

注意:勻速排隊模式暫時不支持 QPS > 1000 的場景,

場景: 對秒殺介面進行流控
在這里插入圖片描述
在這里插入圖片描述
熱點引數限流
何為熱點?熱點即經常訪問的資料,商家不定期做一些“商品秒殺”、“商品推廣”活動,導致“營銷活動”、“商品 詳情”、“交易下單”等鏈路應用出現 快取熱點訪問 的情況:

  • 活動時間、活動型別、活動商品之類的資訊不可預期,導致 快取熱點訪問 情況不可提前預知;
  • 快取熱點訪問 出現期間,應用層少數 熱點訪問 key 產生大量快取訪問請求,沖擊分布式快取系統,大量占據 內網帶寬,最終影回應用層系統穩定性;

很多時候我們希望統計某個熱點資料中訪問頻次最高的 Top K 資料,并對其訪問進行限制,比如:

  • 商品 ID 為引數,統計一段時間內最常購買的商品 ID 并進行限制
  • 用戶 ID 為引數,針對一段時間內頻繁訪問的用戶 ID 進行限制

熱點引數限流會統計傳入引數中的熱點引數,并根據配置的限流閾值與模式,對包含熱點引數的資源呼叫進行限流,熱點引數限流可以看做是一種特殊的流量控制,僅對包含熱點引數的資源呼叫生效,

在這里插入圖片描述
注意:
1. 熱點規則需要使用@SentinelResource(“resourceName”)注解,否則不生效
2. 引數必須是7種基本資料型別才會生效

在這里插入圖片描述

配置熱點引數限流規則
在這里插入圖片描述
測驗: http://localhost:8866/pms/productInfo/26
在這里插入圖片描述
思考: 如何快速且準確的發現熱點訪問key ?

熱點探測功能設計思路
在這里插入圖片描述

三、降級實戰

降級就是當系統的容量達到一定程度時,限制或者關閉系統的某些非核心功能,從而把有限的資源保留給更核心的業務,

比如降級方案可以這樣設計:當秒殺流量達到 5w/s 時,把成交記錄的獲取從展示 20 條降級到只展示 5 條,“從 20 改到 5”這個操作由一個開關來實作,也就是設定一個能夠從開關系統動態獲取的系統引數,

降級的核心目標是犧牲次要的功能和用戶體驗來保證核心業務流程的穩定,是一個不得已而為之的舉措,例如在雙 11 零點時,如果優惠券系統扛不住,可能會臨時降級商品詳情的優惠資訊展示,把有限的系統資源用在保障交易系統正 確展示優惠資訊上,即保障用戶真正下單時的價格是正確的,

3.1 服務降級的策略

在這里插入圖片描述

3.2 應用層降級實戰

場景: 秒殺下單 /order/miaosha/generateOrder
在這里插入圖片描述
如果會員服務出現問題,會影響整個下單鏈路,
模擬查詢會員地址資訊出現網路問題和業務例外

@ApiOperation("顯示識訓地址詳情")
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
@ResponseBody
public CommonResult<UmsMemberReceiveAddress> getItem(@PathVariable Long id,@RequestHeader("memberId") long memberId){
        if(memberId==
        ){
        try{
        //模擬網路問題 
        Thread.sleep(2000);
        }catch(InterruptedException e){
        e.printStackTrace();
        }
        }
        if(memberId==4){
        //模擬業務例外 
        throw new IllegalArgumentException("非法引數例外");
        }
        UmsMemberReceiveAddress address=memberReceiveAddressService.getItem(id,memberId);
        return CommonResult.success(address);
        }

測驗: memberId為3的用戶壓測
在這里插入圖片描述
Sentinel熔斷降級
OpenFeign整合Sentinel
組態檔打開 SentinelFeign 的支持:feign.sentinel.enabled=true

feign: 
sentinel: 
enabled: true

feign介面配置fallbackFactory

@FeignClient(name = "tulingmall‐member", path = "/member",
        fallbackFactory = UmsMemberFeginFallbackFactory.class)
public interface UmsMemberFeignApi {

UmsMemberFeginFallbackFactory中撰寫降級邏輯

@Component
public class UmsMemberFeginFallbackFactory implements FallbackFactory<UmsMemberFeignApi> {
    @Override
    public UmsMemberFeignApi create(Throwable throwable) {
        return new UmsMemberFeignApi() {
            @Override
            public CommonResult<UmsMemberReceiveAddress> getItem(Long id) {
                //TODO 業務降級
                UmsMemberReceiveAddress defaultAddress = new UmsMemberReceiveAddress();
                defaultAddress.setName("默認地址");
                defaultAddress.setId(1L);
                defaultAddress.setDefaultStatus(0);
                defaultAddress.setPostCode("‐1");
                defaultAddress.setProvince("默認省份");
                defaultAddress.setCity("默認city");
                defaultAddress.setRegion("默認region");
                defaultAddress.setDetailAddress("默認詳情地址");
                defaultAddress.setMemberId(1L);
                defaultAddress.setPhoneNumber("199xxxxxx");
                return CommonResult.success(defaultAddress);
            }

            @Override
            public CommonResult<String> updateUmsMember(UmsMember umsMember) {
                return null;
            }

            @Override
            public CommonResult<PortalMemberInfo> getMemberById() {
                return null;
            }

            @Override
            public CommonResult<List<UmsMemberReceiveAddress>> list() {
                return null;
            }
        };
    }
}

會員識訓地址介面配置基于回應時間的降級規則
在這里插入圖片描述
測驗:
在這里插入圖片描述
會員識訓地址介面配置基于例外數的降級規則
在這里插入圖片描述
測驗:
在這里插入圖片描述

四、拒絕服務

拒絕服務可以說是一種不得已的兜底方案,用以防止最壞情況發生,防止因把服務器壓跨而長時間徹底無法提供服務,當系統負載達 到一定閾值時,例如 CPU 使用率達到 90% 或者系統 load 值達到 2*CPU 核數時,系統直接拒絕所有請求,這種方式是最暴力但也最有 效的系統保護方式,
例如秒殺系統,我們可以在以下環節設計過載保護:

  • 在最前端的 Nginx 上設定過載保護,當機器負載達到某個值時直接拒絕 HTTP 請求并回傳 503 錯誤碼, 阿里針對nginx開發的過載保護擴展插件sysguard:https://github.com/alibaba/nginx-http-sysguard
  • 在 Java 層同樣也可以設計過載保護, 比如Sentinel提供了系統規則限流

Sentinel系統規則限流
Sentinel 系統自適應限流從整體維度對應用入口流量進行控制,結合應用的 Load、CPU 使用率、總體平均 RT、入口 QPS 和并發執行緒數等幾個維度的監控指標,通過自適應的流控策略,讓系統的入口流量和系統的負載達到一個平衡,讓 系統盡可能跑在最大吞吐量的同時保證系統整體的穩定性,

  • Load 自適應(僅對 Linux/Unix-like 機器生效):系統的 load1 作為啟發指標,進行自適應系統保護,當系統 load1 超過設定的啟發值,且系統當前的并發執行緒數超過估算的系統容量時才會觸發系統保護(BBR 階段),系統 容量由系統的 maxQps * minRt 估算得出,設定參考值一般是 CPU cores * 2.5,
  • CPU usage(1.5.0+ 版本):當系統 CPU 使用率超過閾值即觸發系統保護(取值范圍 0.0-1.0),比較靈敏,
  • 平均 RT:當單臺機器上所有入口流量的平均 RT 達到閾值即觸發系統保護,單位是毫秒,
  • 并發執行緒數:當單臺機器上所有入口流量的并發執行緒數達到閾值即觸發系統保護,
  • 入口 QPS:當單臺機器上所有入口流量的 QPS 達到閾值即觸發系統保護,

系統規則持久化yml配置

 system‐rules: 
 nacos: 
 server‐addr: tl.nacos.com:8848 
 dataId: ${spring.application.name}‐system‐rules 
 groupId: SENTINEL_GROUP 
 data‐type: json 
 rule‐type: system

在這里插入圖片描述
在這里插入圖片描述

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/310540.html

標籤:其他

上一篇:面試官問到薪資不等的三人:“談談自己對 binder 的理解?”

下一篇:畢業設計:基于STM32單片機的指紋識別/刷卡的門禁/考勤系統

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more