通用數(shù)據(jù)保護(hù)條例(GDPR)是當(dāng)今技術(shù)世界中的重要法規(guī),也是眾多在亞馬遜云科技公有云當(dāng)中建立解決方案的用戶(hù)們所必須遵循的數(shù)據(jù)處理要求。GDPR中提出一項(xiàng)“刪除權(quán)”,或者叫“被遺忘權(quán)”條款,要求通過(guò)實(shí)施相關(guān)解決方案保證刪除特定用戶(hù)的個(gè)人數(shù)據(jù)。
在亞馬遜云科技大數(shù)據(jù)與分析生態(tài)系統(tǒng)的背景之下,每一套架構(gòu),無(wú)論其面向怎樣的目標(biāo),都需要使用Amazon Simple Storage Service(Amazon S3)作為核心存儲(chǔ)服務(wù)。盡管Amazon S3擁有豐富的功能選項(xiàng)與完整性,但卻缺少一種開(kāi)箱即用的機(jī)制將用戶(hù)標(biāo)識(shí)符同包含用戶(hù)數(shù)據(jù)的S3對(duì)象映射起來(lái)。
在本文中,我們將介紹一套框架,幫忙清除您組織中的亞馬遜云科技托管數(shù)據(jù)湖內(nèi)的各特定用戶(hù)數(shù)據(jù)。此外,我們還將共同了解一套由多種不同亞馬遜云科技存儲(chǔ)層構(gòu)成的分析解決方案,以及針對(duì)Amazon S3的示例代碼。
參考架構(gòu)
為了解決數(shù)據(jù)清除框架實(shí)施中的種種挑戰(zhàn),我們?cè)谶@里將問(wèn)題簡(jiǎn)化為一個(gè)簡(jiǎn)單用例,即如何在使用亞馬遜云科技作為數(shù)據(jù)管道的平臺(tái)當(dāng)中實(shí)現(xiàn)用戶(hù)數(shù)據(jù)刪除。下圖說(shuō)明了用例的基本情況。
我們引入了建立并維護(hù)索引元存儲(chǔ)庫(kù)的想法,該存儲(chǔ)庫(kù)能夠跟蹤每位用戶(hù)的記錄位置,幫助我們高效找出這些位置,從而縮小搜索空間。
您可以使用以下架構(gòu),在組織的亞馬遜云科技數(shù)據(jù)湖內(nèi)刪除特定用戶(hù)的數(shù)據(jù)。
對(duì)于此初始版本,我們創(chuàng)建了三個(gè)用戶(hù)流,這些用戶(hù)流負(fù)責(zé)將各項(xiàng)任務(wù)與合適的亞馬遜云科技服務(wù)映射起來(lái):
用戶(hù)流1:實(shí)時(shí)元數(shù)據(jù)存儲(chǔ)更新
S3 ObjectCreated或ObjectDelete事件會(huì)觸發(fā)一項(xiàng)Amazon Lambda函數(shù),此函數(shù)將解析對(duì)象并執(zhí)行添加/更新/刪除操作,以使元數(shù)據(jù)索引保持最新。您也可以為任意其他存儲(chǔ)層建立類(lèi)似的簡(jiǎn)單工作流,具體包括Amazon Relational Database Service(RDS),Amazon Aurora或Amazon Elasticsearch Service(ES)。在本示例中,我們使用Amazon DynamoDB與Amazon RDS for PostgreSQL作為索引元數(shù)據(jù)存儲(chǔ)選項(xiàng),這里使用的具體方法廣泛適用于其他技術(shù)場(chǎng)景。
用戶(hù)流2:清除數(shù)據(jù)
當(dāng)用戶(hù)要求刪除其數(shù)據(jù)時(shí),我們會(huì)通過(guò)Amazon CloudWatch觸發(fā)一個(gè)AWS Step Functions狀態(tài)機(jī)來(lái)協(xié)調(diào)工作流。第一步是觸發(fā)Lambda函數(shù),由該函數(shù)查詢(xún)?cè)獢?shù)據(jù)以識(shí)別出包含用戶(hù)記錄的存儲(chǔ)層,并將生成的報(bào)告保存在S3報(bào)告存儲(chǔ)桶內(nèi)。接下來(lái),由基于Lambda Node JS的工作節(jié)點(diǎn)創(chuàng)建并獲取Step Functions活動(dòng),并通過(guò)Amazon Simple Email Service(SES)將帶有批準(zhǔn)及拒絕鏈接的電子郵件發(fā)送給審核人員。
下圖所示為亞馬遜云科技管理控制臺(tái)上顯示的Step Functions狀態(tài)機(jī)基本架構(gòu)。
審核人員從兩條鏈接中選擇其一,而后調(diào)用Amazon API Gateway端點(diǎn),由該端點(diǎn)調(diào)用Step Functions以恢復(fù)工作流。如果選擇批準(zhǔn)鏈接,則Step Functions將觸發(fā)一項(xiàng)Lambda函數(shù),此函數(shù)將存儲(chǔ)桶內(nèi)的報(bào)告作為輸入,據(jù)此刪除存儲(chǔ)層內(nèi)的對(duì)象或記錄,而后更新索引元存儲(chǔ)庫(kù)。在清除作業(yè)完成之后,Amazon Simple Notification Service(SNS)會(huì)向用戶(hù)發(fā)送操作成功或失敗的通知郵件。
下圖所示,為清除流程成功完成之后,控制臺(tái)上的實(shí)際Step Functions執(zhí)行流。
關(guān)于完整代碼庫(kù),請(qǐng)參閱GitHub repo中的step-function-definition.json文件。
用戶(hù)流3:批量元數(shù)據(jù)存儲(chǔ)更新
此用戶(hù)流主要面向需要?jiǎng)?chuàng)建索引元存儲(chǔ)的現(xiàn)有數(shù)據(jù)湖用例。您可以通過(guò)Amazon Step Functions進(jìn)行流程編排,將歷史數(shù)據(jù)作為輸入并通過(guò)批處理作業(yè)更新元存儲(chǔ)庫(kù)。本文中的實(shí)現(xiàn)方案并不包含此用戶(hù)流的示例腳本。
我們的框架
現(xiàn)在,我們將具體介紹實(shí)現(xiàn)過(guò)程中使用的兩個(gè)用例:
您在每個(gè)Amazon S3文件中存儲(chǔ)有多條用戶(hù)記錄
用戶(hù)將各記錄存儲(chǔ)在同類(lèi)Amazon Web Service存儲(chǔ)層內(nèi)
以這兩種用例為基礎(chǔ),我們將演示實(shí)現(xiàn)索引元數(shù)據(jù)存儲(chǔ)的幾種替代方法。
按S3 URI與行號(hào)建立索引
在此用例中,我們可以使用免費(fèi)的RDS Postgres實(shí)例實(shí)現(xiàn)索引存儲(chǔ)。首先,使用以下代碼創(chuàng)建一個(gè)簡(jiǎn)單表:
CREATE UNLOGGED TABLE IF NOT EXISTS user_objects (
userid TEXT,
s3path TEXT,
recordline INTEGER
);
您可以按user_id建立索引,借此優(yōu)化查詢(xún)性能。在上傳對(duì)象時(shí),您需要在user_objects表中插入用于標(biāo)識(shí)用戶(hù)ID的行、標(biāo)識(shí)目標(biāo)Amazon S3對(duì)象的URI,以及對(duì)應(yīng)的行記錄。例如,當(dāng)上傳以下JSON輸入時(shí),請(qǐng)輸入以下代碼:
{"user_id":"V34qejxNsCbcgD8C0HVk-Q","body":"…"}
{"user_id":"ofKDkJKXSKZXu5xJNGiiBQ","body":"…"}
{"user_id":"UgMW8bLE0QMJDCkQ1Ax5Mg","body ":"…"}
我們將Amazon S3位置s3://gdpr-demo/year=2018/month=2/day=26/input.json元組信息插入到user_objects表中,詳見(jiàn)以下代碼:
(“V34qejxNsCbcgD8C0HVk-Q”,“s3://gdpr-demo/year=2018/month=2/day=26/input.json”,0)
(“ofKDkJKXSKZXu5xJNGiiBQ”,“s3://gdpr-demo/year=2018/month=2/day=26/input.json”,1)
(“UgMW8bLE0QMJDCkQ1Ax5Mg”,“s3://gdpr-demo/year=2018/month=2/day=26/input.json”,2)
您可以在任意Amazon S3 ObjectCreated事件上觸發(fā)Lambda函數(shù),借此實(shí)現(xiàn)對(duì)索引的更新操作。
當(dāng)我們收到來(lái)自用戶(hù)的刪除請(qǐng)求時(shí),則需要查詢(xún)索引以獲取關(guān)于數(shù)據(jù)存儲(chǔ)位置的相關(guān)信息。具體請(qǐng)參見(jiàn)以下代碼:
SELECT s3path,
ARRAY_AGG(recordline)
FROM user_objects
WHERE userid = ‘V34qejxNsCbcgD8C0HVk-Q’
GROUP BY;
以上示例SQL查詢(xún)將返回如下行:
(“s3://gdpr-review/year=2015/month=12/day=21/review-part-0.json“,{2102,529})
輸出表明,S3對(duì)象s3://gdpr-review/year=2015/month=12/day=21/review-part-0.json中的第529行與第2102行中包含請(qǐng)求的用戶(hù)數(shù)據(jù),需要清除。接下來(lái),我們需要下載對(duì)象、刪除這些行,然后覆蓋對(duì)象。關(guān)于實(shí)現(xiàn)此功能的Lambda函數(shù)的Python實(shí)現(xiàn),請(qǐng)參閱GitHub repo中的deleteUserRecords.py。
可用記錄行能夠幫助我們以字節(jié)格式高效執(zhí)行刪除操作。為了簡(jiǎn)化實(shí)施過(guò)程,我們使用空的JSON對(duì)象替換已刪除的行,借此快速實(shí)現(xiàn)行清除。此項(xiàng)操作只會(huì)帶來(lái)少量存儲(chǔ)開(kāi)銷(xiāo),且消除了對(duì)索引內(nèi)的后續(xù)元數(shù)據(jù)行進(jìn)行更新的高成本操作需求。要消除空J(rèn)SON對(duì)象,我們可以采用離線vaccum配合索引更新的方式。
按文件名索引,按索引鍵分組
在此用例中,我們創(chuàng)建了一個(gè)DynamoDB表以存儲(chǔ)索引信息。之所以選擇DynamoDB,是因?yàn)槠鋼碛辛己玫囊子眯耘c可擴(kuò)展性;您可以使用按需計(jì)費(fèi)模型,因此無(wú)需猜測(cè)可能需要的具體容量單位。在將文件上傳至數(shù)據(jù)湖后,Lambda函數(shù)將解析文件名(例如1001-.csv)以標(biāo)記用戶(hù)標(biāo)識(shí)符,并據(jù)此填充DyanmoDB元數(shù)據(jù)表。Userid為分區(qū)鍵,每個(gè)不同存儲(chǔ)層都擁有自己的屬性。例如,如果用戶(hù)1001在Amazon S3及Amazon RDS中擁有數(shù)據(jù),則其記錄將類(lèi)似于以下形式:
{"userid:":1001,"s3":{"s3://path1","s3://path2"},"RDS":{"db1.table1.column1"}}
關(guān)于此功能的Python實(shí)例示例,請(qǐng)參閱GitHub repo中的update-dynamo-metadata.py。
根據(jù)刪除請(qǐng)求,我們需要查詢(xún)?cè)獢?shù)據(jù)存儲(chǔ)表(即DynamoDB)并生成清除報(bào)告,該報(bào)告中包含關(guān)于那些存儲(chǔ)層內(nèi)包含用戶(hù)記錄的詳細(xì)信息,同時(shí)提供有助于加快記錄查找速度的其他提示信息。我們將清除報(bào)告存儲(chǔ)在Amazon S3當(dāng)中。關(guān)于實(shí)現(xiàn)此邏輯的示例Lambda函數(shù),請(qǐng)參閱GitHub repo中的generate-purge-report.py。
在清除獲得批準(zhǔn)之后,我們將使用清除報(bào)告作為輸入,借此刪除所有對(duì)應(yīng)資源。關(guān)于Lambda函數(shù)的實(shí)現(xiàn)示例,請(qǐng)參閱GitHub repo中的gdpr-purge-data.py。
實(shí)現(xiàn)與技術(shù)替代方案
我們探索并評(píng)估了多種實(shí)現(xiàn)方案,意識(shí)到不同的方案各有所長(zhǎng)、也都在某些方面有所妥協(xié),包括實(shí)現(xiàn)方式的簡(jiǎn)單性、執(zhí)行效率、關(guān)鍵數(shù)據(jù)合規(guī)性以及功能完整性等等:
掃描數(shù)據(jù)文件中的每條記錄以創(chuàng)建索引—每次上傳文件時(shí),我們都會(huì)遍歷其記錄并生成元組(包含userid,s3Uri,row_number),而后將其插入至我們的元數(shù)據(jù)存儲(chǔ)層內(nèi)。在刪除請(qǐng)求時(shí),我們將獲取所請(qǐng)求的用戶(hù)ID的元數(shù)據(jù)記錄,下載相應(yīng)的S3對(duì)象,就地執(zhí)行刪除,而后重新上傳經(jīng)過(guò)更新的對(duì)象以覆蓋現(xiàn)有對(duì)象。這是最為靈活的實(shí)現(xiàn)方法,因?yàn)槠渲С滞ㄟ^(guò)單一對(duì)象存儲(chǔ)多個(gè)用戶(hù)的數(shù)據(jù),也成為目前最為常見(jiàn)的普遍實(shí)現(xiàn)方法。但靈活性也有其代價(jià),由于過(guò)程中需要下載并重新上傳對(duì)象,因此刪除操作往往會(huì)帶來(lái)網(wǎng)絡(luò)瓶頸。用戶(hù)活動(dòng)數(shù)據(jù)集(例如客戶(hù)產(chǎn)品評(píng)論)就特別適合使用此種方法,因?yàn)楦鱾€(gè)分區(qū)(例如日期分區(qū))中幾乎很少出現(xiàn)同一用戶(hù)發(fā)布多條記錄的情況,且最好是將多個(gè)用戶(hù)的活動(dòng)合并到單一文件當(dāng)中。參考按S3 URI與行號(hào)建立索引部分的說(shuō)明,您可以在GitHub repo當(dāng)中找到相關(guān)示例代碼。
將元數(shù)據(jù)存儲(chǔ)為文件名前綴—在按查詢(xún)模式定義的不同分區(qū)之下,將用戶(hù)ID設(shè)定為上傳對(duì)象的名稱(chēng)前綴,能夠幫助我們減少刪除請(qǐng)求所需要的搜索操作。元數(shù)據(jù)處理實(shí)用程序能夠從文件名中直接查找用戶(hù)ID,并相應(yīng)執(zhí)行索引維護(hù)操作。這種方法能夠帶來(lái)極高的資源清除效率,但每個(gè)對(duì)象只能對(duì)應(yīng)一個(gè)用戶(hù),且要求我們將用戶(hù)ID存儲(chǔ)在文件名當(dāng)中,這有可能與信息安全要求相違背。這套方案特別適合管理點(diǎn)擊流數(shù)據(jù),在此類(lèi)數(shù)據(jù)流中,會(huì)話(huà)期間單一日期分區(qū)上的單一用戶(hù)將產(chǎn)生多個(gè)點(diǎn)擊事件。根據(jù)我們之前在按文件名索引、按索引鍵分組部分的說(shuō)明,您可以從GitHub rep中下載相關(guān)代碼庫(kù)。
使用元數(shù)據(jù)文件—除了上傳新對(duì)象之外,我們還可以上傳可供索引工具使用的元數(shù)據(jù)文件,借此創(chuàng)建并維護(hù)最新索引。根據(jù)刪除請(qǐng)求,我們可以查詢(xún)索引、借此將我們指向需要清除的記錄位置。此方法最適合在上傳新對(duì)象時(shí),同步上傳對(duì)應(yīng)元數(shù)據(jù)文件的情況(例如上傳多媒體數(shù)據(jù))。在其他場(chǎng)景下,在每一次上傳對(duì)象時(shí)都同時(shí)上傳元數(shù)據(jù)文件,可能給資源容量帶來(lái)沉重壓力。
使用亞馬遜云科技服務(wù)的標(biāo)簽功能—每當(dāng)有新文件被上傳至Amazon S3時(shí),我們都會(huì)使用Put Object Tagging Amazon S3操作為用戶(hù)標(biāo)識(shí)添加鍵值對(duì)。而每當(dāng)出現(xiàn)用戶(hù)數(shù)據(jù)刪除請(qǐng)求時(shí),即可使用該標(biāo)簽獲取對(duì)象并將其刪除。使用現(xiàn)有Amazon S3 API即可輕松實(shí)現(xiàn)這套方案,整個(gè)過(guò)程相當(dāng)輕松易行。但這套方案也面臨著諸多限制,其假定Amazon S3對(duì)象與用戶(hù)之間始終為1:1的關(guān)系(每個(gè)對(duì)象僅包含單一用戶(hù)的數(shù)據(jù));此外,基于標(biāo)簽進(jìn)行對(duì)象搜索的方法效率不高,且將用戶(hù)標(biāo)識(shí)存儲(chǔ)為標(biāo)簽形式的作法也可能有違組織內(nèi)的信息安全要求。
使用Apache Hudi—Apache Hudi已經(jīng)成為Amazon S3之上實(shí)現(xiàn)記錄層級(jí)數(shù)據(jù)刪除功能的一種非常流行的選擇。Hudi的最新版本僅限于Amazon EMR使用,因此只適合從零開(kāi)始構(gòu)建數(shù)據(jù)湖的用戶(hù),即要求您在創(chuàng)建過(guò)程中將數(shù)據(jù)存儲(chǔ)為Hudi數(shù)據(jù)集形式。Hudi項(xiàng)目本身相當(dāng)活躍,預(yù)計(jì)其后續(xù)還將迎來(lái)更多功能,并與更多亞馬遜云科技服務(wù)實(shí)現(xiàn)集成。
在具體方法的選擇當(dāng)中,我們始終要求將數(shù)據(jù)存儲(chǔ)層與元數(shù)據(jù)存儲(chǔ)層區(qū)分開(kāi)來(lái)。因此,這里提出的各種設(shè)計(jì)方案具備良好的通用性,能夠直接插入任何現(xiàn)有數(shù)據(jù)管道當(dāng)中。與選擇數(shù)據(jù)存儲(chǔ)層相似,大家在選擇存儲(chǔ)索引方案時(shí)也需要考慮到以下重要因素:
請(qǐng)求并發(fā)性—如果不打算同時(shí)插入過(guò)多請(qǐng)求,您甚至可以考慮直接將Amazon S3這類(lèi)簡(jiǎn)單存儲(chǔ)方案作為初始索引選項(xiàng)。但如果需要面向眾多用戶(hù)處理多項(xiàng)并發(fā)寫(xiě)入,則最好選擇那些具備更強(qiáng)事務(wù)處理能力的服務(wù)。
考慮團(tuán)隊(duì)的現(xiàn)有專(zhuān)業(yè)知識(shí)與基礎(chǔ)設(shè)施—在本文中,我們演示了如何使用DyanmoDB與RDS Postgres存儲(chǔ)及查詢(xún)?cè)獢?shù)據(jù)索引。如果您的團(tuán)隊(duì)在這方面沒(méi)有任何經(jīng)驗(yàn),而且對(duì)Amazon ES,Amazon DocumentDB(兼容MongoDB)或者其他存儲(chǔ)層的效果基本滿(mǎn)意,不妨直接使用。另外,如果您已經(jīng)擁有一套具備冗余容量的MySQL數(shù)據(jù)庫(kù),也可以將其作為索引實(shí)現(xiàn)方案以節(jié)約運(yùn)營(yíng)成本。
索引大小—元數(shù)據(jù)的體量往往要比實(shí)際數(shù)據(jù)低幾個(gè)量級(jí)。但是,隨著數(shù)據(jù)集規(guī)模的顯著增長(zhǎng),您可能需要考慮采用具備強(qiáng)大可擴(kuò)展能力的分布式存儲(chǔ)解決方案,借此替換傳統(tǒng)的關(guān)系數(shù)據(jù)庫(kù)管理系統(tǒng)。
總結(jié)
GDPR的公布給最佳實(shí)踐帶來(lái)重大影響,也為數(shù)據(jù)湖的設(shè)計(jì)與實(shí)施引入了一系列額外的技術(shù)挑戰(zhàn)。希望本文中提出的參考架構(gòu)與腳本,能夠幫助大家以符合GDPR要求的方式實(shí)現(xiàn)數(shù)據(jù)刪除。
原標(biāo)題:How to delete user data in an AWS data lake